共享内存区
一、概述
-
共享内存区是可用IPC形式中最快的。一旦这样的内存区映射到共享它的进程的地址空间,这些进程间数据的传递就不再涉及内核。
- 往该共享内存区存放信息或从中取走信息的进程间通常需要某种形式的同步,各种形式的同步:互斥锁、条件变量、读写锁、记录锁、信号量。
实现共享内存实现客户-服务器文件复制程序中涉及的步骤:
- 服务器使用一个信号量取得访问某个共享内存区对象的权利。
- 服务器将数据从输入文件读入到该共享内存区对象。read函数的第二个参数所指定的数据缓冲区地址指向这个共享内存区对象。
- 服务器读入完毕时,使用一个信号量通知客户。
- 客户将这些数据从共享内存区对象写出到输出文件中。
此程序只复制两次,一次从输入文件到共享内存区,另一次从共享内存区到输出文件。
二、mmap函数
mmap函数把一个文件或一个Posix共享内存对象映射到调用进程的地址空间。使用该函数的三个目的:
- 使用普通文件以提供内存映射I/O。
- 使用特殊文件以提供匿名内存映射。
- 使用
shm_open
以提供无亲缘关系进程间的Posix共享内存区。
#include<sys/mman.h>
void *mmap(void *addr,size_t len,int port,int flags,int fd,off_t offset);
//addr:指定描述符fd应被映射到进程内存空间的起始地址,通常指定为空指针,自己选择地址。
//len:映射到调用进程地址空间中的字节数,从被映射文件开头起第offset个字节出开始。
//offset通常设置为0。
内存映射区的保护由prot
参数指定,属性值如下:读写模式PROT_READ|PORT_WRITE
。
flags
属性值如下图所示:
-
MAP_SHARED或MAP_PRIVATE
这两个标志必须指定一个并可有选择地或上MAP_FIXED
。 -
若指定了
MAP_PRIVATE
,则调用进程对被映射数据所作的修改只对该进程可见,而不改变其底层支撑对象(或者是一个文件对象,或者是一 个共享内存区对象)。 -
若指定了
MAP_SHARED
,则调用进程对被映射数据所作的修改对于共享该对象的所有进程都可见,而且确实改变了其底层支撑对象。 -
移植性上考虑,
MAP_FIXED
不应该指定 -
若没有指定该标志,但是addr不是一个空指针,那么addr如何处置取决于实现。
-
不为空的addr值通常被当作有关该内存区应如何具体定位的线索。
-
可移植的代码应把addr指定成 一 个空指针,并且不指定
MAP_FIXED
。
父子进程之间共享内存区的方法之 一 :父进程在调用fork前先指定MAP_SHARED
调用mmap。Posix.1保证父进程中的内存映射关系存留到子进程中。而且父进程所作的修改子进程能看到,反过来也 一 样。
三、munmap函数
此函数从某个进程的地址空间删除一个映射关系。
#include<sys/mman.h>
int munmap(void *addr,size_t len);
//addr:mmap返回的地址
//len:映射区的大小。
-
再次访问这些地址将导致向调用进程产生一个
SIGSEGV
信号。 -
若被映射区是使用
MAP_PRIVATE
标志映射,则调用进程对它所作为的变动都会被丢弃。
四、msync函数
-
内核的虚拟内存算法保持内存映射文件( 一 般在硬盘上)与内存映射区 (在内存中)的同步,前提是它是 一 个
MAP_SHARED
内存区。 -
若修改了处于内存映射到某个文件的内存区中某个位置的内容,那么内核将在稍后某个时刻相应地更新文件。
-
确信硬盘上的文件内容与内存映射区中的内容 一 致,于是调用msync来执行这种同步。
#include<sys/mman.h>
int msync(void *addr,size_t len,