【版权声明:尊重原创,转载请保留出处: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系统调用共享内存的更多相关文章

  1. Linux IPC实践(10) --Posix共享内存

    1. 创建/获取一个共享内存 #include <sys/mman.h> #include <sys/stat.h> /* For mode constants */ #inc ...

  2. 细说linux IPC(四):posix 共享内存

    [版权声明:尊重原创.转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途]         上一节讲了由open函数打开一 ...

  3. Linux进程IPC浅析[进程间通信SystemV共享内存]

    Linux进程IPC浅析[进程间通信SystemV共享内存] 共享内存概念,概述 共享内存的相关函数 共享内存概念,概述: 共享内存区域是被多个进程共享的一部分物理内存 多个进程都可把该共享内存映射到 ...

  4. linux下的进程间通信之共享内存

    概念:这种机制允许两个或多个进程通过把公共数据结构放入一个共享内存区来访问它们.如果进程要访问这种数据结构所在的共享内存区,就必须在自己的地址空间中增加一个新线性区,新线性区映射与这个共享内存区相关的 ...

  5. 【网络编程基础】Linux下进程通信方式(共享内存,管道,消息队列,Socket)

    在网络课程中,有讲到Socket编程,对于tcp讲解的环节,为了加深理解,自己写了Linux下进程Socket通信,在学习的过程中,又接触到了其它的几种方式.记录一下. 管道通信(匿名,有名) 管道通 ...

  6. linux c编程:Posix共享内存区

    Posix共享内存区:共享内存是最快的可用IPC形式.它允许多个不相关(无亲缘关系)的进程去访问同一部分逻辑内存.如果需要在两个进程之间传输数据,共享内存将是一种效率极高的解决方案.一旦这样的内存区映 ...

  7. 细说linux IPC(一):基于socket的进程间通信(上)

        [版权声明:尊重原创.转载请保留出处:blog.csdn.net/shallnet 或 .../gentleliu,文章仅供学习交流,请勿用于商业用途]     在一个较大的project其中 ...

  8. 撸代码--linux进程通信(基于共享内存)

    1.实现亲缘关系进程的通信,父写子读 思路分析:1)首先我们须要创建一个共享内存. 2)父子进程的创建要用到fork函数.fork函数创建后,两个进程分别独立的执行. 3)父进程完毕写的内容.同一时候 ...

  9. Linux系统编程——进程间通信:共享内存

    概述 url=MdyPihmS_tWLwgWL5CMzaTrwDFHu6euAJJUAjKvlzbJmRw7RfhmkBWwAloo7Y65hLY-kQdHsbqWYP2wc2fk8yq"& ...

随机推荐

  1. 爬虫必备:Python 执行 JS 代码 —— PyExecJS、PyV8、Js2Py

    在使用爬虫中,经常会遇到网页请求数据是经过 JS 处理的,特别是模拟登录时可能有加密请求.而目前绝大部分前端 JS 代码都是经过混淆的,可读性极低,想理解代码逻辑需要花费大量时间.这时不要着急使用 S ...

  2. Silverlight客户端加载DWG图纸方案

    前段时间一直再研究怎么才能在Silverlight客户端加载 DWG图纸,ArcGIS API For Silverlight中可以加载Shp文件,但是不能加载DWG,最后想出了一个方法步骤如下: 1 ...

  3. Eclipse如何创建模拟器

    Eclipse如何创建模拟器下载地址:http://developer.android.com/sdk/index.html#downloadJDK安装包: 1, 打开安卓模拟器控制台(windows ...

  4. POJ-1696 Space Ant 凸包版花式水过!

                                                         Space Ant 明天早上最后一科毛概了,竟然毫无复习之意,沉迷刷题无法自拔~~ 题意:说实 ...

  5. 【Kubernetes】深入解析声明式API

    在Kubernetes中,一个API对象在Etcd里的完整资源路径,是由:Group(API组).Version(API版本)和Resource(API资源类型)三个部分组成的. 通过这样的结构,整个 ...

  6. 九度oj 题目1337:寻找最长合法括号序列

    题目描述: 给你一个长度为N的,由’(‘和’)’组成的括号序列,你能找出这个序列中最长的合法括号子序列么?合法括号序列的含义便是,在这个序列中,所有的左括号都有唯一的右括号匹配:所有的右括号都有唯一的 ...

  7. HDU——2112HDU Today(SPFA+简单Hash或map+前向星)

    HDU Today Time Limit: 15000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total ...

  8. BZOJ 2301 [HAOI2011]Problem b ——莫比乌斯反演

    分成四块进行计算,这是显而易见的.(雾) 然后考虑计算$\sum_{i=1}^n|sum_{j=1}^m gcd(i,j)=k$ 首先可以把n,m/=k,就变成统计&i<=n,j< ...

  9. RSA工作原理

    摘自:http://www.ruanyifeng.com/blog/2013/07/rsa_algorithm_part_two.html 一.基础数论 1.互质关系 如果两个正整数,除了1以外,没有 ...

  10. linux的crontab定时任务命令

    linux的crontab定时任务命令 cron是一个linux下的定时执行工具. 启动.停止.重启.重新载入配置/sbin/service crond start|stop|restart|relo ...