进程通信
概念
进程通信即进程间的信息交换;
- 进程是资源分配的基本单位,各进程内存空间彼此独立;
- 一个进程不能随意访问其他进程的地址空间;
特点
- 共享存储;
- 消息传递;
- 管道通信;
共享存储
- 基于共享数据结构的通信方式;
- 多个进程公用某个数据结构(OS提供并控制)
- 由用户负责同步处理
- 低级通信:可以传递少量数据,效率低
- 基于共享存储区的通信方式;
- 多个进程公用内存中的一块存储区域
- 由进程控制数据的形式和方式
- 高级通信:可以传递大量数据,效率高
共享存储的通信方式由于多个进程公用空间,数据收发双方不可见,导致在数据操作上存在安全隐患。
消息传递
进程间通过消息传递的方式进行通信,可以分为两类:直接通信、间接通信。
-
直接通信:点到点发送;
- 发送和接收时指明双方进程的ID;
- 每个进程维护一个消息缓冲队列;
-
间接通信:广播信箱;
- 以信箱为媒介,作为中间实体;
- 发进程将消息发送到信箱,收进程从信箱读取;
- 可以广播,容易建立双向通信链;
与共享内存有点类似,区别在于消息传递的间接通信是通过原语实现的。
管道通信
- 管道
- 用于连接读/写进程的共享文件,pipe文件(linux系统是4k);
- 本质是内存中固定大小的缓冲区;
- 半双工通信
- 同一时间只能单向通信(需要让读、写操作互斥),双工通信需要两个管道实现;
- 以先进先出(FIFO)方式组织数据传输;
- 通过系统调用read()/wrete()函数进行读写操作;
需要注意的是,以上三种通信方式是同一计算机中进程的通信方式。而我们通常两个计算机之间的通信,实际上是进程间的通信,只不过是两个计算机的进程通信,他的通信方式不同于以上三种方式。
进程同步
所谓的进程同步,就是协调进程间的相互制约关系,使它们按照预期的方式执行的过程。
- 前提:
- 进程是并发执行的,进程间存在着相互制约关系;
- 并发的进程对系统共享资源进行竞争;
- 进程通信,过程中相互发送的信号成为消息或事件;
- 两种相互制约的形式:
- 间接相互制约的关系(互斥):进程排他性地访问共享资源;
- 直接相互制约的关系(同步):进程间的合作,比如管道通信;
互斥的访问临界资源
访问过程:
- 进入区:尝试进入临界区,成功则加锁(lock);
- 临界区:访问共享资源;
- 退出区:解锁(unlock),唤醒其他阻塞进程;
- 剩余区:其他代码;
repeat
entry section; // 进入区
critical section; // 临界区
exit section; // 退出区
remainder section; // 剩余区
until false;
当共享资源空闲时,多个进程将会进行竞争,竞争成功后加锁并进入临界区;另一方面,对于竞争失败的那些进程,它们会根据尝试竞争(去抢锁)的先后顺序进入阻塞队列中,等待临界资源再次空闲后被唤醒,然后重新竞争。
访问原则
- 空闲让进:临界区空闲,允许一个进程进入;
- 忙则等待:临界区已有进程,其他进程等待(阻塞状态);
- 有限等待:处于等待的进程,等待时间有限;
- 让权等待:等待时应让出CPU执行权,防止”忙等待“;
软件实现方法
- 单标志法:违背”空闲忙进“;
通过设置一个公共变量,指定允许进入临界区的进程ID实现,如上图所示。如果当前进程ID不同于公共变量的值,将会一直处于死循环中进行”忙等待“。可以看出,该方式存在一个严重问题:假如当p0进程离开临界区后,不再进入临界区,那么会导致p1进程永远无法再次进入临界区。
注意:在伪代码中涉及到的while循环是为了便于理解和说明,在实际的操作系统中,实现方式复杂得多,不一定时循环,可以是阻塞队列等数据结构。
- 双标志法先检查:违背”忙则等待“:
上图是双标志法先检查的伪代码说明。将两个标志放置于数组中,元素1代表p0进程是否占用临界区,元素2代表p1进程是否占用临界区。分别只能在没有进程占用临界区时才能进入临界区,否则就会一直处于while循环中。
问题:分析虚线范围的代码,当p0进程刚刚执行完while判断后,在执行修改标识前,此时p1进程如果刚好也在判断while的循环条件,会导致两个进程都成功进入临界区。最终违背了”忙则等待“的互斥原则。
- 双标志法后检查:违背”空闲让进“、”有限等待“;
上图是双标志法后检查的伪代码说明。与双标志法先检查差不多,只不过将while循环条件检查标识的逻辑放到了赋值的后面。
问题:同样,当虚线部分的代码逻辑,p0线程刚刚执行完第一个数组元素的赋值后,p1线程也完成了数组的第二个元素的赋值,这会导致两个线程都无法进入临界区。
- 皮特森算法:违背”让权等待“、会发生”忙等“;
从上图的虚线框中可以看出,即便两个进程在修改turn标识的值前分别将数组中各自的标识设置为了true,但是由于在接下来turn的赋值中,两个值注定是有区别的,因此在while的循环判断中必定会通过一个(当然另一个就不通过);不通过的那个进程会持续的在while循环中运行,知道另一个进程从临界区退出;上面的现象叫做“自旋”。很明显,这种自旋所造成的CPU消耗在一定程度上是可以接受的(比如自旋时间不长的时候)。
硬件实现方法
- 中断屏蔽方法:关中断/开中断
- 禁止一切中断,CPU执行完临界区之前不会切换
- 关中断可能会被滥用
- 关中断时间长影响效率
- 不适用于多处理机,无法防止其他处理机调度其他进程访问临界区
- 只适用于内核进程(因为该指令运行在内核态)
- Test-And-Set(TS指令/TSL指令)
- 读出标志并设置为true,返回旧值,原子操作;
- 也被成为TSL指令;
- 违背“让权等待”,会发生忙等;
- Swap指令(EXCHANGE, XCHG指令)
- 交换两个变量的值,原子操作
- 违背“让权等待”