1. XSI IPC
1.1 标识符和键
有三种IPC称为XSI IPC,即消息队列,信号量以及共享存储器。
每个内核中的IPC结构(消息队列,信号量和共享存储器)都用一个非负整数的标识符(identifier)加以引用。例如,为了对一个消息队列发送消息或取消息,只需知道其队列标识符。当一个IPC结构被创建,以后又被删除时,与这种结构相关的标识符连续加1,直至达到一个整型数的最大值,然后又回到0。
标识符是IPC对象的内部名。键(key)是IPC对象的外部名。无论何时创建IPC结构(调用msgget,semget或shmget),都应该指定一个键。键的数据类型是基本系统数据类型key_t,通常在<sys/types.h>中被定义为长整型。键由内核变成标识符。
客户进程和服务器进程认同一个路径名和项目ID(项目ID是0~255之间的字符值),接着调用ftok将这两个值变成为一个键。然后用该键创建一个新的IPC结构或得到一个的IPC结构。ftok提供的唯一服务就是由一个路径名和项目ID产生一个键。
#include <sys/ipc.h>
key_t ftok(const char *path, int id);
path参数必须引用一个现存文件。当产生键时,只使用id参数的低八位。
三个get函数(msgget,semget和shmget)都有两个类似的参数:一个key和一个整型flag。如果满足以下两个条件之一,则创建一个新的IPC结构:
1). key是IPC_PRIVATE;
2). key当前未与特定类型的IPC结果相结合,并且flag中指定IPC_CREAT位。
为访问现存的队列(通常是客户进程),key必须等于创建该队列时所指定的键,并且不应该指定IPC_CREAT。
如果希望创建一个新的IPC结构,而且要确保不是引用具有同一标识符的一个现行IPC结构,则必须在flag中同时指定IPC_CREAT和IPC_EXCL位。这样做,如果IPC结构已经存在就会出错,返回EEXIST。
1.2. 权限结构
XSI IPC为每个IPC结构设置了一个ipc_perm结构。该结构规定了权限和所有者。
struct ipc_perm{
uid_t uid; // owner's effective user id
gid_t gid; // owner's effective group id
uid_t cuid; // creator's effective user id
gid_t cgid; // creator's effective group id
mode_t mode; // access modes
.
.
.
};
如果想了解你所用系统中它的完整定义,请参见<sys/ipc.h>。
在创建IPC结构时,对所有字段都附初值。调用msgctl、semctl或shmctl修改uid、gid和mode字段。为了改变这些值,调用进程必须是IPC结构的创建者或超级用户。更改这些字段类似于文件调用chown和chmod。
字段mode的值如下所示的值,但是对于任何IPC结构都不存在执行权限。另外,消息队列和共享内存使用术语读(read)和写(write),而信号量则用术语读(rend)和更改(alter)。
权限 | 位 |
用户读(更改) | 0400 |
用户写 | 0200 |
组读 | 0040 |
组写(更改) | 0020 |
其他读 | 0004 |
其他写(更改) | 0002 |
1.3. 结构限制
三种形式的XSI IPC都有内置限制(built-in limit)。这些限制的大多数可以通过重新配置内核而加以更改。
1.4. 优点和缺点
XSI IPC的主要问题是:IPC结构是在系统范围内起作用,没有访问计数。例如:如果进程创建了一个消息队列,在该队列中放入了几则消息,然后终止,但是该消息队列及其内容并不会被删除。它们留在系统中直至出现下述情况:由某个进程调用msgrcv或msgctl读消息或删除消息队列;或某个进程执行ipcrm命令删除该消息队列;或是由正在启动的系统删除消息队列。与管道相比,当最后一个访问管道的进程终止时,管道就被完全删除了。对于FIFO而言,当最后一个引用FIFO的进程终止时,其名字仍保留在系统中,直至显示地删除它,但是留在FIFO中的数据却在此时全部被删除了。
XSI IPC的另一问题:这些IPC结构在文件系统中没有名字,不得不增加新的命令ipcs和ipcrm。
因为这些XSI IPC不使用文件描述符,所以不能对它们使用多路转接I/O函数:select和poll。这使得难于一次使用多个IPC结构,以及文件或设备I/O中使用IPC结构。例如,没有某种形式的忙-等待循环,就不能使一个服务器进程等待将要放在两个消息队列任一个中的消息。