进程间通信(8) - 共享内存(posix)

目录

1.前言

2.共享内存介绍

3.映射函数mmap

4.映射删除munmap

5.映射同步

6.内存映射区的大小

6.1映射文件的大小等于映射长度

6.2映射文件的大小小于映射长度

7.使用mmap进行IPC

7.1匿名内存映射实现亲缘进程IPC

7.2内存映射文件实现无亲缘进程IPC

8.基于mmap的POSIX共享内存实现


1.前言

本篇文章的所有例子,基于RHEL6.5平台(linux kernal: 2.6.32-431.el6.i686)。

2.共享内存介绍

本系列中前面几篇文章,所讲述的Linux下面的各种进程间通信方式,例如:pipe(管道),FIFO(命名管道),message queue(消息队列),它们的共同点都是通过内核来进行通信(假设posix消息队列也是在内核中实现的,因为posix标准没有规定它的具体实现方式)。向pipe,fifo,message queue写入数据时,需要把数据从用户空间(用户进程)复制到内核,而从这些IPC读取数据时,又需要把数据从内核复制到用户空间。
因此,所有的这些IPC方式,都需要在内核与用户进程之间进行2次数据复制,即进程间的通信必须通过内核来传递,如下图1所示:


                 图1:通过内核进行进程间通信(IPC)

共享内存也是一种IPC,它是目前最快的IPC,它的使用方式是将同一个内存区映射到共享它的不同进程的地址空间中,这样这些进程间的通信就不再需要通过内核,只需对该共享的内存区域进程操作就可以了。和其他IPC不同的是,共享内存的使用需要用户自己进行同步操作。
下图2是共享内存区
IPC的通信:

                  图2:共享内存区进程间通信(IPC)

3.映射函数mmap

每个进程都有自己的虚拟地址空间。
我们知道除了堆中的虚拟内存可以由程序员灵活分配和释放,其他区域的虚拟内存都由系统控制,那么还有没有其他方法让程序员去灵活控制虚拟内存呢?
linux下的mmap函数就由此而来。mmap函数可以为我们在进程的虚拟空间开辟一块新的虚拟内存,可以将一个文件映射到这块新的虚拟内存,所以操作新的虚拟内存就是操作这个文件。
因此,mmap函数主要的功能就是将文件或设备映射到调用进程的地址空间中。当使用mmap映射文件到进程后,就可以直接操作这段虚拟地址进行文件的读写等操作,不必再调用read,write等系统调用。
《UNIX网络编程第二卷进程间通信》对mmap函数进行了说明。该函数主要用途有三个:
a)将一个普通文件映射到内存中,通常在需要对文件进行频繁读写时使用,这样用内存读写取代I/O读写,以获得较高的性能。可以提供无亲缘进程间的通信;
b)将特殊文件进行匿名内存映射,可以为亲缘进程提供共享内存空间;
c)为无亲缘的进程提供共享内存空间,一般也是将一个普通文件映射到内存中。

#include <sys/mman.h>  
void *mmap(void *start, size_t len, int prot, int flags, int fd, off_t offset);  
               //成功返回映射到进程地址空间的起始地址,失败返回MAP_FAILED

参数start:指向想要映射的内存起始地址,通常设为 NULL,代表让系统自动选定地址,映射成功后返回该地址。
参数len:映射到进程地址空间的字节数,它从被映射文件开头的第offset个字节处开始,offset通常被设置为0。

参数prot:映射区域的保护方式。可以为以下几种方式的组合:
    ·  PROT_READ:数据可读;
    ·  PROT_WRITE:数据可写;
    ·  PROT_EXEC:数据可执行;
    ·  PROT_NONE:数据不可访问;

参数flags:设置内存映射区的类型标志,POSIX标志定义了以下三个标志:
    · MAP_SHARED:该标志表示,调用进程对被映射内存区的数据所做的修改对于共享该内存区的所有进程都可见,而且确实改变其底层的支撑对象(一个文件对象或是一个共享内存区对象)。
    ·  MAP_PRIVATE:调用进程对被映射内存区的数据所做的修改只对该进程可见,而不改变其底层支撑对象。
    ·  MAP_FIXED:该标志表示准确的解释start参数,一般不建议使用该标志,对于可移植的代码,应该把start参数置为NULL,且不指定MAP_FIXED标志。
    上面三个标志是在POSIX.1-2001标准中定义的,其中MAP_SHARED和MAP_PRIVATE必须选择一个。在Linux中也定义了一些非标准的标志,例如MAP_ANONYMOUS(MAP_ANON),MAP_LOCKED等,具体参考Linux手册。

参数fd:有效的文件描述符。如果设定了MAP_ANONYMOUS(MAP_ANON)标志,在Linux下面会忽略fd参数,而有的系统实现如BSD需要置fd为-1;

参数offset:相对文件的起始偏移。

4.映射删除munmap

    从进程的地址空间中删除一个映射关系,需要用到下面的函数:

#include <sys/mman.h>  
int munmap(void *start, size_t len);   //成功返回0,出错返回-1

参数start:被映射到的进程地址空间的内存区的起始地址,即mmap返回的地址。

参数len:映射区的大小。

5.映射同步

对于一个MAP_SHARED的内存映射区,内核的虚拟内存算法会保持内存映射文件和内存映射区的同步,也就是说,对于内存映射文件所对应内存映射区的修改,内核会在稍后的某个时刻更新该内存映射文件。如果我们希望硬盘上的文件内容和内存映射区中的内容实时一致,那么我们就可以调用msync开执行这种同步:

#include <sys/mman.h>  
int msync(void *start, size_t len, int flags);  //成功返回0,出错返回-1

参数start:被映射到的进程地址空间的内存区的起始地址,即mmap返回的地址。

参数len:映射区的大小。

参数flags:同步标志,有以下三个标志:
    · MS_ASYNC:异步写,一旦写操作由内核排入队列,就立刻返回;
    · MS_SYNC:同步写,要等到写操作完成后才返回。
    . MS_INVALIDATE:使该文件的其他内存映射的副本全部

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值