Linux IPC之POSIX共享内存
来源:互联网 发布:30岁程序员失业怎么办 编辑:程序博客网 时间:2024/05/02 23:21
导言:System V共享内存和共享文件映射,允许无关进程共享内存区域以便执行IPC通信。但这两种技术都存在一些不足:1. System V共享内存模型使用的是键和标识符,这与标准的UNIX I/O模型使用文件名和描述符的做法是不一致的,这种差异意味着使用System V共享内存段需要一整套全新的系统调用和命令。2. 使用一个共享文件映射来进行IPC要求创建一个磁盘文件,即使无需对共享区域进行持久存储也需要这样做,除了因需要创建文件所带来的不便之外,这种技术还会带来一些文件I/O开销。由于存在这些不足,所以POSIX.1b定义了一组新的共享内存API —— POSIX共享内存。
概述
POSIX共享内存能够让无关进程共享一个映射区域,而无需创建一个相应的文件映射。Linux从内核2.4起开始支持POSIX共享内存。SUSv3并没有对POSIX共享内存的实现细节进行规定,特别是没有要求使用一个(真实或虚拟)文件系统来标识共享内存对象,但是很多UNIX实现都采用了文件系统来标识共享内存对象。一些UNIX实现将共享对象名创建为标准文件系统上一个特殊位置处的文件,Linux使用挂载于/dev/shm
目录下的专用tmpfs
文件系统,这个文件系统具有内核持久性,即它所包含的共享内存对象会一直持久,即使当前不存在任何进程打开它,但这些对象会在系统关闭之后丢失。
注意:系统上POSIX共享内存区域占据的内存总量受限于底层的
tmpfs
文件系统的大小,这个文件系统通常会在启动时使用默认大小(如,256MB)进行挂载,如果有必要的话,root用户能够使用命令mount -o remount,size=<num-bytes>
重新挂载这个文件系统来修改它的大小。
要使用POSIX共享内存对象,需要完成下列工作:
- 使用
shm_open()
函数打开一个与指定的名字对应的对象,shm_open()
函数与open()
系统调用类似,它会创建一个新共享对象,或打开一个既有对象。shm_open()
会返回一个引用该对象的文件描述符。 - 将上一步中获得的文件描述符传入
mmap()
调用,并在其flags参数中指定MAP_SHARED
,这会将共享内存对象映射到进程的虚拟地址空间。与mmap()
的其他用法一样,一旦映射了对象之后就能够关闭该文件描述符,而不会影响到这个映射。然后,有可能需要将这个文件描述符保持在打开状态,以便后续的fstat()
和ftruncate()
调用使用这个文件描述符。
说明:
1. POSIX共享内存上shm_open()
和mmap()
的关系类似于System V共享内存上shmget()
和shmat()
的关系。使用POSIX共享内存对象需要两步式过程(shm_open()+mmap()
),而没有使用单个函数来执行两项任务是因为历史原因。在POSIX委员会增加这个特性时,mmap()
调用已经存在了,实际上,这里所需要做的事情是使用shm_open()
调用替换open()
调用,其中差别是使用shm_open()
无需在一个基于磁盘文件系统上创建一个文件。
2. 由于共享内存对象的引用是通过文件描述符来完成的,因此可以直接使用UNIX系统中已经定义好的各种文件描述符系统调用,而无需增加新的系统调用。
使用共享内存对象
#include <fcntl.h> // Defines 0_* constants#include <sys/stat.h> // Defines mode constants#include <sys/mman.h> // returns file descriptor on success, or -1 on errorint shm_open(const char *name, int oflag, mode_t mode);
name
参数标识出了待创建或待打开的共享内存对象。oflag
参数是一个改变调用行为的位掩码。如果oflag
中不包含O_CREAT
,那么就打开一个既有对象,如果指定了O_CREAT
,那么在对象不存在时就创建对象。同时指定O_EXCL
和O_CREAT
能够确保调用者是对象的创建者,如果对象已经存在,就返回一个EEXIST
错误。oflag
参数还表明了调用进程在共享内存对象上的访问模式,其取值为O_RDONLY
或O_RDWR
。而O_TRUNC
会导致在成功打开一个既有共享内存对象之后将对象的长度截断为0。
mode
参数能取的位值与文件上的权限位值是一样的,与open()
系统调用一样,mode
中的权限掩码将会根据进程umask
来取值,与open()
不同的是,在调用shm_open()
时总是需要mode
参数,在不创建新对象时需要将这个参数指定为0。
一个新共享内存对象被创建时,其初始长度会被设置为0,这意味着在创建完一个新共享内存对象之后,通常在调用mmap()
之前需要调用ftruncate()
来设置对象的大小。在调用完mmap()
之后可能还需要使用ftruncate()
来根据需求扩大或收缩共享内存对象。在扩展一个共享内存对象时,新增加的字节会自动被初始化为0。
SUSv3要求POSIX共享内存对象至少具备内核持久性,即它们会持续存在直到被显示删除或系统重启。当不再需要一个共享内存对象时,就应该使用shm_unlink()
删除它。
#include <sys/mman.h>// returns 0 on success, or -1 on errorint shm_unlink(const char *name);
shm_unlink()
函数会删除通过name
指定的共享内存对象。删除一个共享内存对象不会影响对象的既有映射,它会保持有效直到相应的进程调用munmap()
或终止,但会阻止后续的shm_open()
调用打开这个对象。一旦所有进程都解除映射这个对象,对象就会被删除,其中的内容会丢失。
例子
https://github.com/gerryyang/TLPI/tree/master/src/pshm
共享内存API比较
TODO
- Linux IPC之POSIX共享内存
- Linux IPC实践(10) --Posix共享内存
- Linux IPC实践(10) --Posix共享内存
- IPC之Posix共享内存详解
- IPC通信:Posix共享内存
- Linux IPC之共享内存
- Linux IPC之共享内存
- Linux-IPC之共享内存
- Linux IPC之共享内存
- 细说linux IPC(四):posix 共享内存
- 细说linux IPC(四):posix 共享内存
- linux IPC 通信 study 五:posix共享内存
- Linux进程通信之POSIX共享内存
- linux网络编程之POSIX共享内存
- Linux进程通信之POSIX共享内存
- Linux进程通信之POSIX共享内存
- IPC通信:Posix共享内存1
- IPC通信:Posix共享内存2
- python 网络编程学习 http/cookie
- 1013. Battle Over Cities (25)
- python爬虫学习之路(1)_ CSDN网站的模拟登陆
- 树莓派使用 USB 摄像头做网络监控
- A-priori算法的简单实现
- Linux IPC之POSIX共享内存
- 十六进制字符串方法获取颜色
- 数据库事务并发带来的问题
- 水池数目
- Cocos2dx 用户事件 事件监听器 事件分发器
- Android Studio快捷键之Android Studio的下载和安装以及SDK和JDK的导入
- 单调栈
- Angular 2与React比较
- 初学Java Web——Servlet(一)