进程间通信
一.基本概念
竞争条件(race conditions):两个或多个进程读写某些共享数据,而最后的结果取决于进程运行的精确时序,称为竞争条件。
互斥(mutual exclusion):即某种手段以确保当一个进程在使用一个共享变量或文件时,其他进程不能做同样的操作。
临界区(critical region):对共享内存进行访问的程序片段。
适当的安排两个进程不可能同时处于临界区可以避免竞争条件,但并不能保证并发进程能正确高效的进行,一个好的解决方案,需要满足一下四个条件:
1. 任何两个进程不能同时出入临界区
2. 不应对CPU的速度和数目做出任何假设
3. 临界区外的进程不能阻塞其他进程
4. 不得使进程在临界区外无休止的等待
二.互斥的实现方案:
1.禁用中断
每个进程进入临界区后禁用所有中断,在离开之前再开中断。赋予用户进程关闭中断的权利是不明智的,但对于内核本身来说是极为方便的。
2.严格轮换法
int turn=0; //全局变量
//进程0
while(TRUE){
while(turn!=0) ; //wait
critical_region();
turn=1;
Noncritical_region();
}
//进程1
while(TRUE){
while(turn!=1) ; //wait
critical_region();
turn=0;
Noncritical_region();
}
严格轮换法持续的检测某一个变量,直到它具有某一特定的值(忙等待),因此浪费了CPU时间。
再者严格轮换法要求二个严格地轮流进入临界区,若二个进程一个快一个慢,则快的进程可能被处于非临界区的慢进程阻塞。所以,严格轮换法不是一个好的备选方案。
3.Peterson解法
#define FALSE 0 #define TRUE 1 #define N 2 int turn; Int interested[N]; void enten_region(int process) { int other; other=1-process; interested[process]=TRUE; turn=process; while(turn==process && interested[other]==TRUE) ; } void leave_region(int process) { interested[process]=FALSE; }
4.TSL指令
TSL(test and set lock)指令的工作流程如下:它将一个存储器字读到一个寄存器中,然后在该内存地址上存一个非零值。读数和写数操作保证是不可分割的-即该指令结
束之前其他处理机均不允许访问该存储器字。执行TSL指令的CPU将锁住内存总线以禁止其他CPU在本指令结束之前访问内存。
为了使用TSL指令,我们要使用一个共享变量lock来协调对共享内存的访问。当lock为0时,任何进程都可以使用TSL指令将其置为1并读写共享内存。当操作结束时,进程用一条普通的MOVE指令将lock重新置为0。
enter_region: tsl register ,lock //取出lock的值,并将lock设置为1 cmp register, #0 //lock原先是否为0 jne enter_region //不为0则循环测试 ret //返回,进入临界区 leave_region: move lock , #0 //将锁值设为0 ret
5.唤醒与睡眠
Peterson解法和TSL解法都会产生忙等待,使CPU效率降低,还会引起优先级反转问题(priority inversion problem)。
sleep系统调用将引起调用进程阻塞,wakeup系统调用则用于唤醒进程。
考虑当wakeup唤醒一个未阻塞的进程时,导致唤醒信号丢失。可以使用信号量(semaphore)累计唤醒次数供以后使用。
对于信号量可以使用一下两种操作:
DOWN:若其值大于0,则将其减一并继续。若值为0,则进程休眠。
UP:递增信号量的值,若有一个或多个进程在信号量上休眠,无法完成DOWN操作,则系统选择一个并允许其完成DOWN操作,信号量值仍为0。
DOWN和UP操作均为不可分割的原子操作。