Linux 核心--6.进程间通讯机制( 三 )



进程允许进行非阻塞读(这依赖于它们打开文件或者管道的方式) , 此时如果没有数据可读或者管道被加锁 ,  则返回错误信息表明进程可以继续执行 。阻塞方式则使读者进程在管道inode的等待队列上睡眠直到写者 进程结束 。当两个进程对管道的使用结束时 , 管道inode和共享数据页面将同时被遗弃 。

Linux还支持命名管道(named pipe) , 也就是FIFO管道 , 因为它总是按照先进先出的原则工作 。第一个被写入 的数据将首先从管道中读出来 。和其它管道不一样 , FIFO管道不是临时对象 , 它们是文件系统中的实体并且 可以通过mkfifo命令来创建 。进程只要拥有适当的权限就可以自由使用FIFO管道 。打开FIFO管道的方式稍有不同 。其它管道需要先创建(它的两个file数据结构 , VFS inode和共享数据页面)而FIFO管道已经存在 , 只需要由使用者打开与关闭 。在写者进程打开它之前 , Linux必须让读者进程先打开此FIFO管道;任何读者进程从中读取之前必须有写者进程向其写入数据 。FIFO管道的使用方法与普通管道基本相同 , 同时它们使用相同数据结构和操作 。


5.3套接口

5.3.1系统V IPC机制
Linux支持Unix系统V(1983)版本中的三种进程间通讯机制 。它们是消息队列、信号灯以及共享内存 。这些系统V IPC机制使用共同的授权方法 。只有通过系统调用将标志符传递给核心之后 , 进程才能存取这些资源 。这些系统V IPC对象使用与文件系统非常类似的访问控制方式 。对象的引用标志符被用来作为资源表中的索引 。这个索引值需要一些处理后才能得到 。
系统中所有系统V IPC对象的Linux数据结构包含一个ipc_perm结构 , 它含有进程拥有者和创建者及组标志符 。另外还有对此对象(拥有者 , 组及其它)的存取模式以及IPC对象键 。此键值被用来定位系统V IPC对象的引用标志符 。这样的键值一共有两组:公有与私有 。如果此键为公有 , 则系统中任何接受权限检查的进程都可以找到系统V IPC对象的引用标志符 。系统V IPC对象绝不能用一个键值来引用 , 而只能使用引用标志符 。


5.3.2消息队列
消息队列允许一个或者多个进程向它写入与读取消息 。Linux维护着一个msgque消息队列链表 , 其中每个元素 指向一个描叙消息队列的msqid_ds结构 。当创建新的消息队列时 , 系统将从系统内存中分配一个msqid_ds结构 , 同时将其插入到数组中 。





图5.2 系统V IPC消息队列

每个msqid_ds结构包含一个ipc_perm结构和指向已经进入此队列消息的指针 。另外 , Linux保留有关队列修改时间信息 , 如上次系统向队列中写入的时间等 。msqid_ds包含两个等待队列:一个为队列写入进程使用而另一个由队列读取进程使用 。

每次进程试图向写入队列写入消息时 , 系统将把其有效用户和组标志符与此队列的ipc_perm结构中的模式进行比较 。如果允许写入操作 , 则把此消息从此进程的地址空间拷贝到msg数据结构中 , 并放置到此消息队列尾部 。由于 Linux严格限制可写入消息的个数和长度 , 队列中可能容纳不下这个消息 。此时 , 此写入进程将被添加到这个消息队列的等待队列中 , 同时调用调度管理器选择新进程运行 。当由消息从此队列中释放时 , 该进程将被唤醒 。

从队列中读的过程与之类似 。进程对这个写入队列的访问权限将被再次检验 。读取进程将选择队列中第一个消息(不管是什么类型)或者第一个某特定类型的消息 。如果没有消息可以满足此要求 , 读取进程将被添加 到消息队列的读取等待队列中 , 然后系统运行调度管理器 。当有新消息写入队列时 , 进程将被唤醒继续执行 。

推荐阅读