UNIX环境高级编程——IPC总结

     IPC主要包括:管道,消息队列,信号量,共享内存, 套接字(SOCKET)。


一、IPC对象的持久性

     每种IPC机制都会借助一种数据结构,这种数据结构的实例称为该IPC机制的对象(相应的,用于同步互斥的数据结构的实体也可以称为该机制的对象)。理清IPC对象的持久性,有助于理解相应的IPC的工作机制。


1.对象持久性

     大致上IPC对象的持久性可以分为三种:
  • 进程持久性:具有这种持久性的对象在持有它的最后一个进程关闭了该对象时就会消失。
  • 内核持久性:具有这种持久性的对象在两种情形下会消失,(1)系统重启(2)它被显式的删除
  • 文件系统持久性:具有这种持久性的对象只有在它被显式删除时才会消失。

     下表是常见的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包含:

  • System V消息队列
  • System V信号量
  • System V共享内存区
System V IPC具有一些共同的属性,使用key_t类型的值作为其名字;每个IPC对象有一个与之关联的ipc_perm结构、IPC权限。


1.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
}; 

4.创建与打开IPC通道
     创建或打开一个IPC对象的三个getXXX函数的都需要一个类型为key_t的IPC键的key值,并且返回一个整数标识符。该标识符不同于ftok函数的id参数。对于key值,应用程序有两种选择:
  • 调用ftok,给它传递pathname和id;
  • 指定key为IPC_PRIVATE,这将保证会创建一个新的、唯一的IPC对象;
     三个getXXX函数,都有一个oflag参数,他指定IPC对象的读写权位,并选择是创建一个新的IPC对象还是访问一个已存在的IPC对象,规则如下:
1.key指定为IPC_PRIVATE能保证创建一个唯一的IPC对象。没有一对id和pathname的组合会导致ftok产生IPC_PRIVATE这个键值;
2.设置oflag参数的IPC_CREAT位但不设置它的IPC_EXCL位时,如果指定键的IPC对象不存在,那就创建一个新对象,否则返回该对象;
3.设置oflag参数的IPC_CREAT位和它的IPC_EXCL位时,如果所指定键的IPC对象不存在,那就创建一个新的对象,否则返回一个EEXIST错误,因为该对象已经存在;
4.如果要访问一个已经存在的IPC,就不能指定IPC_PRIVATE标记,因为这是一个特殊的用于创建IPC对象的键值

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
MSG_W

SEM_R
SEM_A

SHM_R
SHM_W

组读
组写(更改)

MSG_R>>3
MSG_W>>3

SEM_R>>3
SEM_A>>3

SHM_R>>3
SHM_W>>3

其他读
其他写(更改)

MSG_R>>6
MSG_W>>6

SEM_R>>6
SEM_A>>6

SHM_R>>6
SHM_W>>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的多数实现有内在的内核限制,例如消息队列的最大数目、每个信号量集的最大信号量数等。
另外还存在一些缺点:

  • IPC结构是在系统范围内起作用的,没有访问计数。例如,如果创建了一个消息队列,在该队列中放入了几则消息,然后终止,但是该消息队列及其内容并不被删除。它们余留在系统中直至:由某个进程调用msgrcv或msgctl读消息或删除消息队列,或某个进程执行ipcrm命令删除消息队列;或由正在再启动的系统删除消息队列。
  • 这些IPC结构并不按名字为文件系统所知。因此不能用常规的文件系统函数来存取它们或修改它们的特性。为了支持它们不得不增加了十多个全新的系统调用(msgget、semop、shmat等)。不能用ls命令见到它们,不能用rm命令删除它们,不能用chmod命令更改它们的存取权。于是,也不得不增加了全新的命令ipcs和ipcrm。
  • 这些IPC不使用文件描述符,所以不能对它们使用多路转接I/O函数:select和poll。

posted on 2013-07-15 17:16  胡永光  阅读(183)  评论(0编辑  收藏  举报

导航