一、IPC对象的持久性
每种IPC机制都会借助一种数据结构,这种数据结构的实例称为该IPC机制的对象(相应的,用于同步互斥的数据结构的实体也可以称为该机制的对象)。理清IPC对象的持久性,有助于理解相应的IPC的工作机制。
1.对象持久性
大致上IPC对象的持久性可以分为三种:下表是常见的IPC对象以及用于同步互斥的对象的持久性
类型 |
持久性 |
管道 FIFO |
进程持久性 进程持久性 |
Posix互斥锁 Posix条件变量 Posix读写锁 Fcntl记录锁 |
进程持久性 进程持久性 进程持久性 进程持久性 |
System V消息队列 System V信号量 System V共享内存 |
内核持久性 内核持久性 内核持久性 |
TCP socket UDP socket Unix域socket |
进程持久性 进程持久性 进程持久性 |
从表中看没有一种对象的持久性是文件系统的。这也是合理的,因为很少有进程能不受系统重启的影响;而且使用文件系统持久性也可能会降低该IPC机制的性能。
2.调用fork,exec,_exit对IPC对象及同步互斥对象的影响
类型 |
fork |
exec |
_exit |
管道和FIFO |
子进程获得父进程的所有打开的描述符的拷贝 |
除非描述符的FD_CLOSEXEC比特被置位了,否则描述符保持打开状态 |
所有描述符都被关闭,在描述符最后一次被关闭时,管道或FIFO中的数据会被删除 |
System V信号量 |
所有的semadj的值在子进程中被设置为0 |
所有的semadj的值被传递给新的程序 |
所有的semadj的值被加到相应的信号量上 |
System V消息队列 |
没影响 |
没影响 |
没影响 |
System V共享内存 |
父进程中已连接上的共享内存被子进程保留 |
去除内存映射 |
去除内存映射 |
mmap共享内存 |
父进程的共享内存被子进程保留 |
去除内存映射 |
去除内存映射 |
Posix互斥锁和条件变量 |
如果在共享内存中并且设置了进程共享属性则就被共享 |
除非位于仍被打开的共享内存中并且具有进程共享属性否则就将消失 |
除非位于仍被打开的共享内存中并且具有进程共享属性否则就将消失 |
Posix读写锁 |
如果在共享内存中并且设置了进程共享属性则就被共享 |
除非位于仍被打开的共享内存中并且具有进程共享属性否则就将消失 |
除非位于仍被打开的共享内存中并且具有进程共享属性否则就将消失 |
fcntl记录锁 |
父进程持有的锁不会被子进程所继承 |
只要描述保持打开,锁就不会因为exec的动作而变化 |
所有被进程持有的锁都会被释放 |
二、System V IPC
System V IPC包含:
|
消息队列 |
信号量 |
共享内存 |
头文件 |
<sys/msg.h> |
<sys/sem.h> |
<sys/shm.h> |
创建、打开或删除IPC |
msgget |
semget |
shmget |
控制IPC操作 |
msgctl |
semctl |
shmctl |
IPC操作 |
msgsend msgrcv |
semop |
shmat shmdt |
2.key_t键和ftok函数
三种类型的System V IPC使用key_t值作为他们的名字。头文件<sys/types.h>把key_t这个数据类型定义为一个整数,它通常是一个至少32位的整数。这些整数值通常是ftok函数赋赋予的。
函数ftok把一个已经存在的路径和一个整数标识符转换为一个key_t值,叫IPC键(IPC key).
ftok典型的实现调用stat函数,然后组合以下三个值:
1. pathname所在文件系统的信息;
2. 该文件在本文件系统内的索引节点号;
3. id的低序8位;
如果pathname不存在或者当前进程不能访问该文件,则ftok返回-1,另外需要注意的是其pathname用于产生key的文件在使用ftok产生的key的进程运行期间不能被创建和删除,因为每次文件被创建,它会需要一个新索引结点编号,这就会导致下次使用ftok时获得了一个不同的key。
3.ipc_perm结构
内核给每个IPC对象维护一个信息结构,其内容跟内核给文件维护的信息类似。
struct ipc_perm { uid_t uid;//owner的用户ID gid_t gid;//owner的组ID uid_t cuid;//creater的用户ID gid_t cgid;//creater的组ID mode_t mode;//读写模式 ulong_t seq;//序列号 key_t key;//IPC key };
5.IPC权限
创建一个新的IPC对象时,以下信息就保存该对象的ipc_perm结构中:
1. oflag参数中某些比特会初始化ipc_perm结构的mode成员。
2. cuid和cgid成员分别设置为调用进程的有效用户ID和有效组ID。这两个成员合称为创建者ID。
3. ipc_perm结构的uid和gid成员也分别设置为调用进程的有效用户ID和有效组ID。这两个成员合称为所有者ID。
在创建IPC结构时,除seq以外的所有字段都赋初值。以后,可以调用msgctl、semctl或shmctl修改uid、gid和mode字段。为了改变这些值,调用进程必须是IPC结构的创建者或超级用户。
许可权 |
消息队列 |
信号量 |
共享内存 |
用户读 |
MSG_R |
SEM_R |
SHM_R |
组读 |
MSG_R>>3 |
SEM_R>>3 |
SHM_R>>3 |
其他读 |
MSG_R>>6 |
SEM_R>>6 |
SHM_R>>6 |
需要注意的是:
1.创建者ID永远不会改变,但是进程可以通过IPC机制中的IPC_SET命令修改所有者ID。三个getXXX没有使用UNIX的文件创建模式掩码,IPC对象的权限被设置为指定的值。Posxi IPC非常类似文件,但是System V IPC在权限的存储上是与文件系统的不同的,它的权限不受文件创建模式掩码的影响。
2.任意进程要访问一个IPC对象都需要经历两个层级的检查:一个在IPC对象被打开时(检查是否指定了未包含在ipc_perm结构中的模式,因为创建的IPC对象的权限是存在于ipc_perm结构中的),一个在IPC对象被使用时(过程类似于PosixIPC的权限检查)。
6.ipcs和ipcrm程序
由于System V IPC的三种类型不是以文件系统中路径名标识的,因此使用标准的ls和rm程序无法看到它们,也无法删除他们。不过实现了这些类型IPC的任何系统都提供两个特殊的程序:ipcs和ipcrm。ipcs输出有关System V IPC特性的各种信息,ipcrm则删除一个System V消息队列、信号量集或共享储存区。
7.内核限制
System V IPC的多数实现有内在的内核限制,例如消息队列的最大数目、每个信号量集的最大信号量数等。
另外还存在一些缺点: