7.4 POSIX 共享内存

前面提到的内存映射允许无关进程共享内存区域以执行相应的 IPC,但具有一些缺点,比如它需要在硬盘上创建相应的文件,存在额外的 IO 开销。为了克服这些缺点,提出了 共享内存 API。 使用 POSXI 共享内存一般需要以下步骤:

  1. 使用 shm_open函数打开一个共享内存对象,此函数返回一个引用该对象的文件描述符。

  2. 将上一步获得的文件描述符传入 mmap调用并指定 flags 参数中指定 MAP_SHARED,即可将共享内存对象映射到虚拟地址空间。此文件描述符上可以调用传统 Unix 文件描述符系统调用。

创建共享内存对象

shm_open 函数创建和打开一个新的共享内存对象或打开一个既有对象,它的参数与 open 函数类似:

#include <fcntl.h>
#include <sys/stat.h>
#include <sys/mman.h>

/*
@brief	打开一个文件
@param	name		标识出了待创建或待打开的共享内存对象
@param	flags		掩码表,可取:
                	- O_CREAT  对象不存在时创建,若同时指定 O_EXCL,则对象存在时返回错误
                        - O_RDONLY 只读访问
                        - O_RDWR   读写访问
                        - O_TRUNC  将对象截断为 0
@param	mode		标识文件的所有权限,在创建共享内存对象时使用
			仅仅打开一个已有对象需要将其设置为 0
                	- S_IRUSR | S_IWUSR 属主的读写权限
                        - S_IRGRP | S_IWGRP	数组的读写权限
                        - S_IROTH | S_IWOTH	其它的去写权限
@return	成功返回文件描述符,失败返回 -1
*/

int shm_open(const char *name, int oflag, mode_t mode);

shm_open返回的文件描述符会设置 close-on-exec 标记,因此当程序执行了一个 exec 时文件描述符会被自动关闭。 共享内存对象在创建后其初始长度会被设置为 0,所以在调用 mmap 之前调用 ftruncate来设置对象的大小。并且在内存映射后继续调用 ftruncate 来操作映射内存大小。

删除共享内存对象

SUSv3 要求 POSIX 共享内存对象至少具备内核持久性,即它们会持续存在直到被显式删除或系统重启。当不再需要一个共享内存对象时就应该使用shm_unlink删除它:

#include <sys/mman.h>

int shm_unlink(const char *name);

shm_unlink函数会删除通过 name 指定的共享内存对象。删除一个共享内存对象不会影响对象的既有映射(它会保持有效直到相应的进程调用 munmap 或终止),但会阻止后续的 shm_open 调用打开这个对象。一旦所有进程都解除映射这个对象,对象就会被删除,其中的内容会丢失。

最后更新于