4.2.7 进程通信
并发执行的进程为了协同工作,相互之间必须传送各种各样的数据。进程之间相互交换数据的过程称为进程通信。
1.进程通信的类型
·低级通信:进程间控制信息的交换称为低级通信。如信号量机制和管程机制。
·高级通信:进程间大批数据的交换称为高级通信。
因此,进程之间的互斥、同步以及数据交换统称为进程通信。
2.进程高级通信的主要模式(模型)
(1)共享内存模式
建立一块协作进程共享的内存区域,进程通过对此共享区读写数据来交换信息。
(2)消息传递模式
协作进程间通过使用操作系统提供的两个原语send和receive进行信息交换,从而实现通信。
共享内存方式中,进程共享一个内存区域,并且需要程序员编写访问和操作内存的代码。消息传递方式则由操作系统提供机制,使协作进程通过消息传递工具进行通信,适用于较少数据量的交换,对于计算机间的通信,消息传递比共享内存更容易实现。消息传递方式在分布式环境中特别有用。但共享内存可以达到最快、最方便的通信效果,在采用共享内存通信模式的系统中,仅在建立共享内存区域时需要系统调用,一旦建立好,就不再需要来自内核的帮助,所有的访问都被视为常规的内存访问。而采用消息传递模式的系统常通过系统调用来实现,需要依靠内核的帮助。
3.共享内存模式
共享内存模式最早是在UNIX System V中作为进程通信的一部分而设计的。它是目前系统进程通信中最高效的方式之一。该机制可以将内存中的一个区域与多个进程的虚拟地址空间相连接。需要通信的进程读取数据就像读自己的数据一样方便。
在主存中开辟共享主存区,需要通信的进程将自己的虚拟地址空间映射到共享主存区,一组进程向该共享主存区中写,另一组从中读,以此实现两组或者两组以上进程间的信息交换。
4.消息传递模式
消息传递模式是单处理机计算机系统、多处理机计算机系统以及计算机网络中本地进程通信主要采用的一种进程高级通信方式。消息是一组按照规定格式组织的信息,由消息头和消息体组成。采用消息传递机制,进程间可以使用消息来交换信息。通过操作系统提供的两个高级通信原语:send和receive,正在执行的进程可以在任何时刻向另一个正在执行的进程发送或请求消息。消息传递时执行send,接收者要接收消息时执行receive。
消息传递模式有两种实现方式:直接方式和间接方式。
(1)直接方式
接收、发送消息时要指明对方进程(或线程),每对进程之间自动建立一个双向消息队列。常采用消息缓冲机制。
首先,在发送进程和接收进程之间必须使用公用的消息缓冲区。消息缓冲区是队列结构。两个进程之间传送数据时,必须满足如下条件:
1)在发送进程把消息写入消息缓冲区,并将消息缓冲区挂在接收进程PCB的消息队列期间,应禁止其他进程对该缓冲区消息队列的访问;否则,将引起消息队列的混乱。
2)当接收进程正从自己的消息队列中取下消息缓冲区时,也应禁止其他进程对该消息队列的访问。
其次,设公用信号量mutex为控制对缓冲区访问的互斥信号量,其初值为1;rm为发送进程的私用信号量,表示可以接收发送进程的消息缓冲区个数,其初值为n;sm为接收进程的私用信号量,表示等待接收的消息个数,其初值为0。设发送进程调用send(m)将消息m送往缓冲区,接收进程调用receive(m)将消息m从缓冲区读往自己的数据区。send和receive的系统调用(用P、V操作来实现send原语和receive原语)描述如图4-5所示。
图 4-5 send和receive的系统调用
(2)间接方式
接收、发送消息时不需要指明对方进程(或线程),只要指明是哪个消息队列,每个消息队列可以与多个进程相关,每个进程可以通过多个通信队列与其他进程通信。
通常采用信箱方式,此时的消息队列称为信箱或端口。发送进程发消息时不指定接收进程的名字,而是指定一个中间媒介,即信箱。进程间通过这个共享的信箱实现通信,解除了发送进程和接收进程的直接联系。
信箱由信箱头和信箱体组成。信箱一般分为:私有信箱、公用信箱和共享信箱。
1)私有信箱是由用户进程为自己创建的,信箱的创建者有权读信息,其他用户进程只能向该信箱发消息。私有信箱随着创建进程的撤销而消失。
2)公用信箱是由操作系统创建的,系统中所有核准的进程既可以将消息发到信箱中,也可以从信箱中读出发送给自己的消息。
3)共享信箱是由用户创建的属性为共享的信箱。该信箱的创建者和指定共享者既可以将消息发到信箱中,也可以从信箱中读出发送给自己的消息。
信箱是一个有容量的资源,使用时要遵循以下规则:
1)若发送信件时信箱已满,则置发送进程为“等信箱”状态,直到信箱有空时才被唤醒。
2)若取信件时信箱中无信,则置接收进程为“等信件”状态,直到有信件时才被唤醒。
信箱通信通过操作系统提供的两个高级通信原语send和receive来实现。
1)send实现
send(MB,M)//把信件M送到指定的信箱N中
查找指定信箱MB,若信箱未满,则把信件M送入信箱且释放“等信件”者;若信箱已满,置发送信件进程为“等信箱”状态。
2)receive实现
receive(MB,N)//从指定信箱N中取出一封信,存放到指定的地址X中
查找指定信箱MB,若信箱中有信,则取出一封信存于N中且释放“等信箱”者;若信箱中无信,则置接收信件进程“等信件”状态。