IPC之共享内存
共享内存区介绍
进程间通讯有很多方法,其中最快的形式要数共享内存。
从实现标准上来说,共享内存可分为POSIX共享内存区和System V 共享内存区,从概念上来是是类似的。
两个进程直接访问同一段共享内存。减少了数据的复制次数和上下文切换成本,
但是这种快是有代价的,那就是没有内核来帮你维护数据同步,两个进程同时能够访问这段内存,会造成数据同步问题,这个时候需要使用到锁来解决这个问题,不过这篇文章暂时不涉及到锁,我们详细的来了解下内存映射的概念。
从实现标准上来说,共享内存可分为POSIX共享内存区和System V 共享内存区,从概念上来是是类似的。
POSIX共享内存区
每个进程都拥有操作系统虚拟给自己的一段连续的私有内存区域,但是多个进程要共享一段内存就需要操作系统从空闲内存池中分配,分配好以后,需要连接它的进程进行申请连接,这个过程就叫做共享内存映射。映射完成后,每个进程就可以像访问自己的私有内存一样去访问共享内存区域,从而跟其他进程进行通讯。请看下图:
上图很清晰的描述了共享内存的原理,但是该怎么操作才能申请共享内存呢?接下来我会详细描述这个过程。
进程分为有亲缘关系进程和无亲缘关系进程,它们的通讯方式也不尽相同。 有亲缘关系的进程间共享内存有三种办法。
- 使用内存映射文件,open函数打开。
- BSD系列的系统提供了匿名内存映射标识
MAP_ANONYMOUS
直接映射内存。 - 打开
/dev/zero
设备文件匿名映射。
/dev/zero在类UNIX系统中是一个特殊的设备文件,当你读它的时候,它会提供无限的空字符。 Link 维基百科
无亲缘关系的进程间共享内存有两种办法:
- 内存映射文件,open函数打开。
- 共享内存区对象,通过
shm_open
函数打开一个POSIX IPC名称。
函数的使用
使用POSIX共享内存区要用到shm_open
,shm_unlink
,ftruncate
,mmap
,munmap
等函数,接下来我为大家详细说明。
shm_open
创建或打开一个IPC对象。
函数原型:
|
|
参数:
- name 这是一个"Posix IPC名字",符合已有的路径名规则,必须是斜杠符
/
开头,可以是真实的路径名,也可以不是。 - oflag 可选标识有
O_RDONLY
,O_RDWR
,O_CREAT
,O_EXCL
,O_NONBLOCK
,O_TRUNC
,其中O_RDONLY
,O_RDWR
两个标识必须有一个存在。 - mode 创建一个新的消息队列,信号量或共享内存区对象时,需要设置这个权限位参数,权限位参数值如下:
常值 | 说明 |
---|---|
S_IRUSR | 用户(属主)读 |
S_IWUSR | 用户(属主)写 |
S_IRGRP | (属)组成员读 |
S_IWGRP | (属)组成员读写 |
S_IROTH | 其他用户读 |
S_IWOTH | 其他用户写 |
shm_unlink
删除一个IPC对象。跟所有其他unlink函数一样,删除一个IPC对象不会影响对于其底层支撑对象的已存在引用,只有该对象的所有引用全部关闭,这个对象才会清除。删除一个IPC对象仅仅是为了防止后续对其调用。
函数原型:
|
|
ftruncate
该函数可以调整指定对象的大小,无论是普通文件还是共享内存区对象都可以调节。只是针对这两个类型的操作稍微有些不同。
- 对于普通文件。如果该文件的大小大于length参数,那么额外的数据就会被丢弃掉。
- 对于一个共享内存对象,该函数把这个对象的大小设置成length字节。 函数原型:
|
|
fstat
获取指定对象的信息。
函数原型:
|
|