XSI IPC相同特征

有三种IPC我们称作XSI IPC,即消息队列、信号量和共享内存,它们之间有很多相似之处。

本篇博客主要介绍它们相似的特征,若想了解它们的不同之处,可以查看消息队列、信号量、共享内存

一、标识符和键

 每个内核中的IPC结构(消息队列、信号量、共享内存)都用一个非负整数的标识符加以引用。例如:为了对一个消息队列发送或者获取消息,只需要知道其队列标识符。与文件描述符不同,IPC标识符不是小的整数。当一个IPC结构被创建,以后又被删除时,与这种结构相关的标识符连续加1,直至达到一个整型数的最大正值,然后又回转到0。

 标识符是IPC对象的内部名。为使多个合作进程能够在同一IPC对象上会合,需要提供一个外部名方案。为此使用了键,每个IPC对象都与一个键相关联,于是键就用作为该对象的外部名。

无论何时创建IPC结构(调用msgget、semget或shmget),都应指定一个键,键的数据类型是基本系统数据类型key_t,通常在头文件中被定义为长整型。键由内核变换成标识符。

有多种方法使客户进程和服务器进程在同一IPC结构上会和:

 (1)服务器进程可以指定键IPC_PRIVATE创建一个新IPC结构,将返回的标识符存放在某处(例如一个文件)以方便客户进程取用。键IPC_PRIVATE保证服务器进程创建一个新IPC结构。这种技术的缺点是:服务器进程要将整型标识符写到文件中,此后客户进程又要读文件取得此标识符。

 IPC_PRIVATE键也可用于父、子进程关系。父进程指定IPC_PRIVATE创建一个新IPC结构,所返回的标识符在调用fork后可由子进程使用。接着,子进程又可将此标识符作为exec函数的一个参数传给一个新程序。

(2)在一个公用文件中定义一个客户进程和服务器进程都认可的键。然后服务器进程指定此键创建一个新的IPC结构。这种方法的问题是改键可能已与一个IPC结构相结合,在此情况下,get函数(msgget、semget或shmget)出错返回。服务器进程必须处理这一错误,删除已存在的IPC结构,然后试着在创建它。

(3)客户进程和服务器进程认同一个路径名和项目ID(项目ID是0——255之间的字符值),接着调用函数ftok将这两个值变换为一个键。然后在方法(2)中使用此键。ftok提供的唯一服务就是由一个路径名和项目ID产生一个键。

#include

key_t ftok(const char* path,int id);
                            //返回值:若成功则返回键,若出错则返回(key_t)-1

参数path必须引用一个现存文件。当产生键时,只使用id参数的低8位。

  ftok创建的键通常是用下列方式构成的:按给定的路径名取得其stat结构,其结构如下:

struct stat{
mode_t      st_mode;
ino_t       st_ino;
dev_t       st_dev;
dev_t       st_rdev;
nlink_t     st_nlink;
uid_t       st_uid;
gid_t       st_gid;
off_t       st_size;
time_t      st_atiem;
time_t      st_mtime;
time_t      st_ctime;
blksize_t   st_blksize;
blkcnt_t    st_blocks;
};

从该结构中取出部分st_dev和st_ino字段,然后再与项目ID组合起来。如果两个路径名引用两个不同的文件,那么,对这两个路径名调用ftok通常返回不同的键。但是,因为i节点号和键通常都存放在长整型中,于是创建键时可能会丢失信息。这意味着,如果使用同一个项目ID,那么对于不同文件的两个路径名可能产生相同的键。

三个get函数(msgget、semget和shmget)都有两个类似的参数:一个key和一个整型flag。如若满足下列两个条件之一,则创建一个新的IPC结构(通常由服务器进程创建):

key是IPC_PRIVATE;

key当前未与特定类型的IPC结构相结合,并且flag中指定了IPC_CREAT位。

为访问现存的队列(通常由客户进程进行),key必须等于创建该队列时所指定的键,并且不应指定IPC_CREAT。

注意,为了访问一个现存队列,绝不能指定IPC_PRIVATE作为键。因为这是一个特殊的键值,它总是用于创建一个新队列。为了访问一个用IPC_PRIVATE键创建的现存队列,一定要知道与该队列相结合的标识符,然后在其它IPC调用中(例如msgsnd和msgrcv)使用该标识符。

如果希望创建一个新的IPC结构,而且要确保不是引用具有同一标识符的一个现行IPC结构,那么必须在flag中同时指定IPC_CREAT和IPC_EXCL位。这样做了以后,如果IPC结构已经存在就会造成出错,返回EEXIST。

二、权限结构

XSI IPC为每一个IPC结构设置了一个ipc_perm结构。该结构规定了权限和所有者。他至少包括下列成员:

 struct ipc_perm{     
              uid_t             uid;               /*共享内存所有者的有效用户ID */
              gid_t             gid;              /* 共享内存所有者所属组的有效组ID*/
              uid_t             cuid;            /* 共享内存创建者的有效用户ID*/
              gid_t             cgid;           /* 共享内存创建者所属组的有效组ID*/
              unsigned short    mode;          /* Permissions + SHM_DEST和SHM_LOCKED标志*/
              unsignedshort     seq;          /* 序列号*/
.
.
.
};

每种实现在其ipc_perm结构中会包括另外一些成员。

在创建IPC结构时,对所有字段都赋初值。以后,可以调用msgctl、semctl或shmctl修改uid、gid和mode字段。为了改变这些值,调用进程必须是IPC结构的创建者或超级用户。更改这些字段名类似于对文件调用chown和chmod。

mode字段的值类似于下表所示的值,但是对任何IPC结构都不存在执行权限。

XSI IPC相同特征_第1张图片

下表对每种IPC说明了6种权限:

XSI IPC相同特征_第2张图片

某些实现定义了表示每种权限的符号常量,但是这些常量并不包含在Single UNIX Specification中。

三、结构限制

   三种形式的XSI IPC都有内置限制。这些限制的大多数可以通过重新配置内核而加以更改。

缺点

 (1)IPC结构是在系统范围内起作用的,没有访问计数。

      例如:如果进程创建了一个消息队列,在该队列中放了几则消息,然后终止,但是该消息队列及其内容并不会删除。它们余留在系统中直至出现了以下情况:

  1. 由某个进程调用msgrcv读消息或调用msgctl删除消息队列

  2. 某个进程之陷阱ipcrm(1)命令删除消息队列

  3. 由正在再启动的系统删除消息队列

    与无名管道相比,当最后一个访问无名管道的进程终止时,无名管道就被完全地删除了。

    与命名管道FIFO相比,虽然当最后一个引用FIFO的进程终止时其名字仍保留在系统中,直至显式地删除它,但是留在FIFO中的数据却在此时全部删除了,于是也就徒有其名了。

(2)IPC结构在文件系统中没有名字。为了访问它们或者修改他们的特性,不得不增加十几条全新的系统调用(msgget、semop、shmat等)。我们不能使用ls命令看见到IPC对象,不能使用rm命令删除它们。也不能用chmod命令更改它们的访问权限。于是,就不得不增加新的命令ipcs(1)和ipcrm(1)。

(3)因为这些IPC不使用文件描述符,所以不能对它们使用多路转接I/O函数:select和poll。这就使得难于一次使用多个IPC结构,以及在文件或设备I/O中使用IPC结构。例如,没有某种形式的忙-等待循环,就不能使一个服务器进程等待将要放在两个消息队列任一个中的消息。

优点

(1)可靠

(2)流是受控的(“流控制”指的是:如果系统资源(缓冲区)短缺或者如果接收进程不能再接收更多消息,则发送进程就要休眠。当流控制条件消失时,发送进程应自动被唤醒)

(3)面向记录

(4)可以使用非先进先出方式处理

 

你可能感兴趣的:(Linux,XSI,IPC,消息队列,信号量,共享内存)