共享内存—内存映射 mmap 收藏
共 享内存可以说是最有用的进程间通信方式,也是最快的 IPC 形式。两个不同进程 A、B 共享内存的意思
是,同一块物理内存被映射到进程 A、B 各自的进程地址空 间。进程 A 可以即时看到进程 B 对共享内存中
数据的更新,反之亦然。由于多个进程共享同一块内存区域,必然需要某种同步机制,互斥锁和信号量都
可以。
采用共享内存通信的一个显而易 见的好处是效率高,因为进程可以直接读写内存,而
不需要任何数据的拷贝。对于像管道和消息队列等通信方式,则需要在内核和用户空间进行
四次的数据拷贝,而 共享内存则只拷贝两次数据[1]:一次从输入文件到共享内存区,另一
次从共享内存区到输出文件。实际上,进程之间在共享内存时,并不总是读写少量数据后就
解除映射,有新的通信时,再重新建立共享内存区域。而是保持共享区域,直到通信完毕
为止,这样,数据内容一直保存在共享内存中,并没有写回文件。共享内存 中的内容往往
是在解除映射时才写回文件的。因此,采用共享内存的通信方式效率是非常高的。
Linux 的 2.2.x 内核支持多 种共享内存方式,如 mmap()系统调用,Posix 共享内存,
以及系统 V 共享内存。linux 发行版本如 Redhat 8.0 支持 mmap()系统调用及系统 V 共
享内存,但还没实现 Posix 共享内存,本文将主要介绍 mmap()系统调用及系统 V 共享内
存 API 的原理及应 用。
一、内核怎样保证各个进程寻址到同一个共享内存区域的内存页面
1、 page cache 及 swap cache 中页面的区分:一个被访问文件的物理页面都驻留
在 page cache 或 swap cache 中,一个页面的所有信息由 struct page 来描述。struct
page 中有一个域为指针 mapping ,它指向一个 struct address_space 类型结构。page
cache 或 swap cache 中的所有页面就是根据 address_space 结构以及一个偏移量来区
分的。
2、文件与 address_space 结构的对应:一个具体的文件在打开后,内核会在内存中
为之建立一个 struct inode 结构,其中的 i_mapping 域指向一个 address_space 结构。
这样,一个文件就对应一个 address_space 结构,一个 address_space 与一个偏移量能
够确定一个 page cache 或 swap cache 中的一个页面。因此,当要寻址某个数据时,很
容易根据给定的文件及数据在文件内的偏移量而找到相应的页面。
3、进程调用 mmap()时,只是在进程空间内新增了一块相应大小的缓冲区,并设置
了相应的访问标识,但并没有建立进程空间到物理页面的映射。因此,第一次访问该空间时,
会引发一个缺页异常。
4、 对于共享内存映射情况,缺页异常处理程序首先在 swap cache 中寻找目标页
(符合 address_space 以及偏移量的物理页),如果找到,则直接返回地址;如果没有找