细说linux IPC(三):mmap系统调用共享内存
【版权声明:尊重原创,转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途】
前面讲到socket的进程间通信方式。这样的方式在进程间传递数据时首先须要从进程1地址空间中把数据复制到内核,内核再将数据复制到进程2的地址空间中,也就是数据传递须要经过内核传递。这样在处理较多数据时效率不是非常高。而让多个进程共享一片内存区则攻克了之前socket进程通信的问题。共享内存是最快的进程间通信 。将一片内存映射到多个进程地址空间中,那么进程间的数据传递将不在涉及内核。
共享内存并非从某一进程拥有的内存中划分出来的。进程的内存总是私有的。共享内存是从系统的空暇内存池中分配的,希望訪问它的每一个进程连接它。这个连接过程称为映射。它给共享内存段分配每一个进程的地址空间中的本地地址。
mmap()系统调用使得进程之间通过映射同一个普通文件实现共享内存。普通文件被映射到进程地址空间后。进程能够向訪问普通内存一样对文件进行訪问。不必再调用read(),write()等操作。
函数原型为:
#include <sys/mman.h>
void *mmap(void *addr, size_t length, int prot, int flags, int fd, off_t offset);
当中參数addr为描写叙述符fd应该被映射到进程空间的起始地址,当指定为NULL时内核将自己去选择起始地址,不管addr是为NULL,函数返回值都是fd所映射到内存的起始地址;
len是映射到调用进程地址空间的字节数,它 从被映射文件开头offset个字节開始算起,offset通常设置为0;
prot 參数指定共享内存的訪问权限。可取例如以下几个值的或:PROT_READ(可读) , PROT_WRITE (可写), PROT_EXEC (可运行), PROT_NONE(不可訪问)。该值常设置为PROT_READ | PROT_WRITE 。
flags由下面几个常值指定:MAP_SHARED , MAP_PRIVATE , MAP_FIXED,当中,MAP_SHARED(变动是共享的,对共享内存的改动全部进程可见) , MAP_PRIVATE(变动是私有的。对共享内存改动仅仅对该进程可见) 必选其一,而MAP_FIXED则不推荐使用 。
munmp() 删除地址映射关系。函数原型例如以下:
#include <sys/mman.h>
int munmap(void *addr, size_t length);
參数addr是由mmap返回的地址。len是映射区大小。
进程在映射空间的对共享内容的改变并不直接写回到磁盘文件里。往往在调用munmap()后才运行该操作。能够通过调用msync()实现磁盘上文件内容与共享内存区的内容一致。 msync()函数原型为:
#include <sys/mman.h>
int msync(void *addr, size_t length, int flags);
參数addr和len代表内存区,flags有下面值指定,MS_ASYNC(运行异步写), MS_SYNC(运行同步写),MS_INVALIDATE(使快速缓存失效)。当中MS_ASYNC和MS_SYNC两个值必须且仅仅能指定一个,一旦写操作排入内核。MS_ASYNC马上返回,MS_SYNC要等到写操作完毕后才返回。假设还指定了MS_INVALIDATE,那么与其终于拷贝不一致的文件数据的全部内存中拷贝都失效。
在使用open函数打开一个文件之后调用mmap把文件内容映射到调用进程的地址空间,这样我们操作文件内容仅仅须要对映射的地址空间进行操作。而无需再使用open。write等函数。
使用共享内存的步骤基本是:
open()创建内存段;
用 ftruncate()设置它的大小。
用mmap() 把它映射到进程内存,运行其它參与者须要的操作;
当使用完时,原来的进程调用 munmap()然后退出。
以下来看一个实现:
server程序创建内存并向共享内存写入数据:
int sln_shm_get(char *shm_file, void **shm, int mem_len)
{
int fd;
fd = open(shm_file, O_RDWR | O_CREAT, 0644);//1. 创建内存段
if (fd < 0) {
printf("open <%s> failed: %s\n", shm_file, strerror(errno));
return -1;
}
ftruncate(fd, mem_len);//2.设置共享内存大小
*shm = mmap(NULL, mem_len, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0); //mmap映射系统内存池到进程内存
if (MAP_FAILED == *shm) {
printf("mmap: %s\n", strerror(errno));
return -1;
}
close(fd);
return 0;
}
int main(int argc, const char *argv[])
{
char *shm_buf = NULL;
sln_shm_get(SHM_IPC_FILENAME, (void **)&shm_buf, SHM_IPC_MAX_LEN);
snprintf(shm_buf, SHM_IPC_MAX_LEN, "hello share memory ipc! i'm server.");
return 0;
}
client程序映射共享内存并读取当中数据:
int main(int argc, const char *argv[])
{
char *shm_buf = NULL;
sln_shm_get(SHM_IPC_FILENAME, (void **)&shm_buf, SHM_IPC_MAX_LEN);
printf("ipc client get: %s\n", shm_buf);
munmap(shm_buf, SHM_IPC_MAX_LEN);
return 0;
}
先执行server程序向共享内存写入数据,再执行客户程序。执行结果例如以下:
# ./server
# ./client
ipc client get: hello share memory ipc! i'm server.
#
共享内存不像socket那样本身具有同步机制,它须要通过添加其它同步操作来实现同步,比方信号量等。同步相关操作在后面会有相关专栏具体叙述。
本节源代码下载:
http://download.csdn.net/detail/gentleliu/8140487
最后今天祝各位单身程序员节日快乐!。!!!
细说linux IPC(三):mmap系统调用共享内存的更多相关文章
- Linux IPC实践(10) --Posix共享内存
1. 创建/获取一个共享内存 #include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #inc ...
- 细说linux IPC(四):posix 共享内存
[版权声明:尊重原创.转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] 上一节讲了由open函数打开一 ...
- Linux进程IPC浅析[进程间通信SystemV共享内存]
Linux进程IPC浅析[进程间通信SystemV共享内存] 共享内存概念,概述 共享内存的相关函数 共享内存概念,概述: 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到 ...
- linux下的进程间通信之共享内存
概念:这种机制允许两个或多个进程通过把公共数据结构放入一个共享内存区来访问它们.如果进程要访问这种数据结构所在的共享内存区,就必须在自己的地址空间中增加一个新线性区,新线性区映射与这个共享内存区相关的 ...
- 【网络编程基础】Linux下进程通信方式(共享内存,管道,消息队列,Socket)
在网络课程中,有讲到Socket编程,对于tcp讲解的环节,为了加深理解,自己写了Linux下进程Socket通信,在学习的过程中,又接触到了其它的几种方式.记录一下. 管道通信(匿名,有名) 管道通 ...
- linux c编程:Posix共享内存区
Posix共享内存区:共享内存是最快的可用IPC形式.它允许多个不相关(无亲缘关系)的进程去访问同一部分逻辑内存.如果需要在两个进程之间传输数据,共享内存将是一种效率极高的解决方案.一旦这样的内存区映 ...
- 细说linux IPC(一):基于socket的进程间通信(上)
[版权声明:尊重原创.转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途] 在一个较大的project其中 ...
- 撸代码--linux进程通信(基于共享内存)
1.实现亲缘关系进程的通信,父写子读 思路分析:1)首先我们须要创建一个共享内存. 2)父子进程的创建要用到fork函数.fork函数创建后,两个进程分别独立的执行. 3)父进程完毕写的内容.同一时候 ...
- Linux系统编程——进程间通信:共享内存
概述 url=MdyPihmS_tWLwgWL5CMzaTrwDFHu6euAJJUAjKvlzbJmRw7RfhmkBWwAloo7Y65hLY-kQdHsbqWYP2wc2fk8yq"& ...
随机推荐
- 在loadrunner中用头文件的形式对字符串进行MD5加密操作
1.首先要有md5.h的头文件 2.然后在global.h中加入#include "md5.h" 3.在action中调用md5.h中的Change_to_Md5(const ch ...
- 高性能MySQL(第三版)
一.MySQL架构与历史 1.2.2 锁粒度 表锁:写锁的优先级高于读锁:写锁的请求可以插入到读锁的前面,但读锁的请求却不能插入到写锁的前面: 行级锁:行级锁只在存储引擎层实现,在服务器层没有实现: ...
- 00051_static关键字
1.static概念 当在定义类的时候,类中都会有相应的属性和方法.而属性和方法都是通过创建本类对象调用的.当在调用对象的某个方法时,这个方法没有访问到对象的特有数据时,方法创建这个对象有些多余.可是 ...
- hdu3594 Cactus
仙人掌入门简单题. 先看一篇文档. #include <iostream> #include <cstring> #include <cstdio> using n ...
- BZOJ3130 [Sdoi2013]费用流 【网络流 + 二分】
题目 Alice和Bob在图论课程上学习了最大流和最小费用最大流的相关知识. 最大流问题:给定一张有向图表示运输网络,一个源点S和一个汇点T,每条边都有最大流量.一个合法的网络流方案必须满足:(1)每 ...
- 算法复习——带修改莫队(bzoj2453)
题目: Description 你小时候玩过弹珠吗? 小朋友A有一些弹珠,A喜欢把它们排成队列,从左到右编号为1到N.为了整个队列鲜艳美观,小朋友想知道某一段连续弹珠中,不同颜色的弹珠有多少.当然,A ...
- 【2018.4.5】Shoi2017题集
这三道题分别对应bzoj4868~4870,pdf没法往这放,因此放弃了. T1: 方法1(正解):三分法 考虑暴力枚举最晚公布的时间x,关注到2操作是没有负面影响的1操作,所以如果A大于B,那么只需 ...
- spring 如何动态加载properties文件的内容
1. 在xml中配置你的properties路径: <bean id="messageSource" class="org.springframework.cont ...
- idea下springboot打包成jar包和war包,并且可以在外部tomcat下运行访问到
接着上一章走呗:http://www.cnblogs.com/sxdcgaq8080/p/7712874.html 然后声明一点,下面打包的过程中,scope一直都是使用默认的范围 <!--用于 ...
- Lucas 卢卡斯定理
Lucas: 卢卡斯定理说白了只有一条性质 $$ C^n_m \equiv C^{n/p}_{m/p} \times C^{n \bmod p}_{m \bmod p} \ (mod \ \ p) $ ...