Unix 中进程间的通信

进程间通信(IPC,Interprocess communication)是一组编程接口,让程序员能够协调不同的程序进程,使之能在一个操作系统里同时运行。这使得一个程序能够在同一时间里处理许多用户的要求。因为即使只有一个用户发出要求,也可能导致一个操作系统中多个进程的运行,进程之间必须互相通话。IPC接口就提供了这种可能性。每个IPC方法均有它自己的优点和局限性,因此,对于单个程序而言使用所有的IPC方法是不常见的。

进程间通信主要包括系统IPC(进程间通信)(包括消息队列,信号,共享存储), 套接字(SOCKET),管道(PIPLE),信号量集

一、信号机制
1.信号机制的基本概念
  信号机制主要是作为在同一用户的诸进程之间通信的简单工具。信号本身是一个1~19中的某个整数,用来代表某一种事先约定好的简单消息。每个进程在执行时,都要通过信号机制来检查是否有信号到达。若有信号到达,表示某进程已发生了某种异常事件,便立即中断正在执行的进程,转向由该信号(某整数)所指示的处理程序,去完成对所发生的事件(事先约定)的处理。处理完毕,再返回到此前的断点处继续执行。可见,信号机制是对硬中断的一种模拟,故在早期的UNIX版本中又称其为软中断。

   信号机制与中断机制之间的相似之处表现为:信号和中断都同样采用异步通信方式,在检测出
   有信号或有中断请求时,两者都是暂停正在执行的程序而转去执行相应的处理程序,处理完后
   都再返回到原来的断点;再有就是两者对信号或中断都可加以屏蔽。

信号与中断两机制之间的差异是:中断有优先级,而信号机制则没有,即所有的信号都是平等的;再者是信号处理程序是在用户态下运行的,而中断处理程序则是在核心态下运行;还有,中断响应是及时的,而对信号的响应通常都有较长的时间延迟。

   2.信号机制的功能

1) 发送信号
  这是指由发送进程把信号送至指定目标进程的proc结构中信号域的某一位上。如果目标进程正在一个可被中断的优先级上睡眠,核心便将目标进程唤醒,发送过程就此结束。一个进程可能在其信号域中有多个位被置位, 代表已有多种类型的信号到达, 但对于一类信号, 进程却只能记住其中的某一个。进程可利用系统调用kill向另一进程或一组进程发送一个信号。

2) 设置对信号的处理方式
  在UNIX系统中,可利用系统调用signal(sig,func)来预置对信号的处理方式。其中, 参数sig为信号名,func用于预置处理方式,可分成三种情况:
  (1) func=1时,进程对sig类信号不予理睬,亦即屏蔽了该信号。
  (2) func=0,即为缺省值时,进程在收到sig信号后应自我终止。

(3) func为非0、非1类整数时,就把func的值作为指向某信号处理程序的指针。

  1. 对信号的处理
      当一个进程要进入或退出一个低优先级睡眠状态时,或一个进程即将从核心态返回到用户态时,核心都要检查该进程是否已收到信号。当进程处于核心态时,即使收到信号也不予理睬;仅当进程返回到用户态时,才处理信号。对信号的处理分三种情况进行:当func=1时,进程不做任何处理便返回;当func=0时,进程自我终止;当其值为非0、非1的整数时,系统从核心态转为用户态后,便转向相应信号的处理程序(因为该程序是用户程序,故应运行在用户态),处理完后,再返回到用户程序的断点。

二、管道机制
1.管道的类型
   1) 无名管道(Unnamed Pipes)
  在早期的UNIX版本中,只提供了无名管道。这是一个临时文件,是利用系统调用pipe( )建立起来的无名文件(指无路径名)。 只用该系统调用所返回的文件描述符来标识该文件, 因而,只有调用pipe的进程及其子孙进程才能识别此文件描述符,从而才能利用该文件(管道)进行通信。当这些进程不再需要此管道时,由核心收回其索引结点。

  2) 有名管道(Named Pipes)

为了克服无名管道在使用上的局限性,以便让更多的进程能够利用管道进行通信,在UNIX系统中又增加了有名管道。有名管道是利用mknod系统调用建立的、可以在文件系统中长期存在的、具有路径名的文件,因而其它进程可以感知它的存在,并能利用该路径名来访问该文件。对有名管道的访问方式像访问其它文件一样,都需先用Open系统调用将它打开。不论是有名管道、还是无名管道,对它们的读写方式是相同的。

2.对无名管道的读写
  1) 对pipe文件大小的限制
  为了提高进程的运行效率,pipe文件只使用索引结点中的直接地址i-addr(0)~i-addr(9)。如果每个盘块的大小为4 KB, 则pipe文件的最大长度被限制在40 KB之内。 核心将索引结点中的直接地址项作为一个循环队列来管理,为它设置一个读指针和一个写指针, 按先进先出顺序读写。

  1. 进程互斥
      为使读、写进程互斥地访问pipe文件,只须使诸进程互斥地访问pipe文件索引结点中的直接地址项。因此,每逢进程在访问pipe文件前,都须先检查该索引结点是否已经上锁。 若已锁住,进程便睡眠等待;否则,将索引结点上锁,然后再执行读、写操作。操作结束后又将该索引结点解锁,并唤醒因该索引结点上锁而睡眠的进程。

  2. 进程写管道
      当进程向管道写数据时,可能有以下两种情况:如果管道中有足够的空间能存放要写的数据,在每写完一(盘)块后,核心便自动增加地址项的大小。当写完i-addr(9)地址项中所指示的盘块时,便又向i-addr(0)地址项所指示的盘块中写数据,全部写完后,核心修改索引结点中的写指针,并唤醒因该管道空而睡眠等待的进程。如果管道中无足够的空间来存放要写入的数据,核心将对该索引结点做出标志,然后让写进程睡眠等待,直到读进程将数据从管道中读出后,才唤醒等待写进程

  3. 进程读管道
      当进程从管道中读数据时,也同样会有两种可能:如果管道中已有足够的数据供进程读,读进程便根据读指针的初始值去读数据。每读出一块后,便增加地址项的大小。读完时,核心修改索引结点中的读指针,并唤醒所有等待的写进程。如果进程所要读的数据比管道中的数据多,则可令读进程把管道中已有数据读完后,暂时进入睡眠状态等待,直至写进程又将数据写入管道后,再将读进程唤醒。


三、消息机制

  1. 消息(message)
      消息是一个格式化的、可变长度的信息单元。消息机制允许进程发送一个消息给任何其它进程。由于消息的长度是可变的,因而为便于管理而把消息分为消息首部和消息数据区两部分。在消息首部中,记录了消息的类型和大小且指向消息数据区的指针以及消息队列的链接指针等是定长的。在图10-6 中示出了消息队列i中的三个消息首部msgh0、msgh3和msgh2。它们分别利用一个指向缓冲区(数据区)的指针指出消息的位置。
    Unix 中进程间的通信
  2. 消息队列
      当一个进程收到由其它多个进程发来的消息时,可将这些消息排成一个消息队列,每个消息队列有一个称为关键字key的名称,它是由用户指定的。每个消息队列还有一个消息队列描述符,其作用与用户文件描述符一样,以方便用户和系统对消息队列的访问。在一个系统中可能有若干个消息队列,由所有的消息队列的头标组成一个头标数组。

2.消息队列的建立与操作
  1) 消息队列的建立
  在一个进程要利用消息机制与其它进程通信之前,应利用系统调用msgget( )先建立一个指名的消息队列。对于该系统调用,核心将搜索消息队列头标表,确定是否有指定名字的消息队列。若无,核心将分配一个新的消息队列头标,并对它进行初始化,然后给用户返回一个消息队列描述符;否则,它只是检查该消息队列的许可权后便返回。

  1. 消息队列的操纵
      用户可利用msgctl( )系统调用对指定的消息队列进行操纵。在该系统调用中包括三个参数,其中,msgid为消息队列描述符;cmd是规定的命令;buf是用户缓冲区地址,用户可在此缓冲区中存放控制参数和查询结果。命令可分为三类:(1) 用于查询有关消息队列的情况的命令,如查询队列中的消息数目、队列中的最大字节数、最后一个发送消息的进程的标识符、发送时间等。(2) 用于设置和改变有关消息队列的属性的命令,如改变消息队列的用户标识符、用户组标识符、消息队列的许可权等。 (3) 消除消息队列的标识符。

3.消息的发送和接收
  1. 消息的发送
  当进程要与其它进程通信时,可利用msgsnd( )系统调用来发送消息。对于msgsnd( )系统调用,核心检查消息队列描述符和许可权是否合法,消息长度是否超过系统规定的长度。 通过检查后,核心为消息分配消息数据区,并将消息从用户消息缓冲区拷贝到消息数据区。分配消息首部,将它链入消息队列的末尾;在消息首部中填写消息的类型、大小以及指向消息数据区的指针等;还要修改消息队列头标中的数据(如消息队列中的消息数、字节数等)。然后,唤醒在等待消息到来的睡眠进程。

  1. 消息的接收
      进程可利用msgrcv( )系统调用,从指定消息队列中读一个消息。对于msgrcv( )系统调用,先由核心检查消息队列标识符和许可权,继而根据用户指定的消息类型做相应的处理。消息类型msgtyp的参数可能有三种情况:当msgtyp=0时,核心寻找消息队列中的第一个消息,并将它返回给调用进程;当msgtyp为正整数时,核心返回指定类型的第一个消息;当msgtyp为负整数时,核心应在其类型值小于或等于msgtyp绝对值的所有消息中,选出类型值最低的第一个消息返回。如果所返回消息的大小等于或小于用户的请求,核心便将消息正文拷贝到用户区,再从队列中删除该消息,并唤醒睡眠的发送进程;如果消息长度比用户要求的大,则系统返回出错信息。用户也可忽略对消息大小的限制,此时,核心无需理会消息的大小而一概把消息内容拷贝到用户区。
上一篇:UNIX进程间通信


下一篇:Linux