代码改变世界

进程同步、互斥和前驱关系基础

2014-01-01 21:11  hduhans  阅读(2159)  评论(0)    收藏  举报

  进程间同步、互斥和前驱关系的实线是操作系统进程管理中的一个难点,也是一个重点,必须掌握。这三种关系主要是利用信号量来实现对应的关系。

一、基本概念

  ① 进程同步:基于进程间的直接制约关系,由于进程之间存在某种合作关系,是进程间共同完成一项任务时直接发生相互作用的关系。例如数据处理进程必须等待数据提供进程提供数据后才开始执行处理动作。经典的生产者消费者问题就是进程同步的问题

  ② 进程互斥:基于进程间的间接制约关系,是并发执行的多个进程由于竞争同一资源而产生相互排斥的关系。当临界区没有空闲资源时,其他访问临界资源的进程必须等待,等空闲资源被释放后再去访问。例如多个打印进程打印时都需要独占打印机,因此这些进程之间具有互斥关系。注意这里并非只能允许一个进程访问临界资源,当临界资源数量大于1时,可以允许同时有多个进程访问临界资源。

  ③ 进程间的前驱关系:进程间按一定的顺序执行。

二、进程互斥同步的四大原则

  ① 空闲让进:只要临界资源空闲,就应该允许进程进入;

  ② 忙则等待:临界资源正在被访问时,其他进程必须等待;

  ③ 有限等待:对于等待临界资源的进程,必须保证能在有限时间内进入临界资源,避免“死等”;

  ④ 让权等待:当进程不能进入临界区时,应立即释放处理机,以免进程进入“忙等”状态。这里的权可以理解为指CPU,当自身进程不能进入临界区的时候,应该放弃CPU使用权,进入等待状态;

  举一个例子加深理解:多个打印进程在工作时,只要打印机处于空闲状态,就应该允许打印进程去使用它(空闲让进)。当打印机正在打印时,其他打印进程必须等待打印机空闲后再使用(忙则等待)。正在排队等待打印机的进程,必须保证他们能在有限的时间内获取打印机资源,避免“死等”的情况(有限等待)。当一个打印机无法获取打印机资源时,应该立即释放CPU资源,让CPU为其他进程服务,避免自身进入无效的“忙等”状态(让全等待)。

三、信号量的作用

  信号量分为整型信号量和记录型信号量,二者的区别是整型信号量使用的是while循环不断测试,会产生“忙等待”。而记录型信号量则是一个结构体,变量内保存了等待的进程列表,避免了“忙等待”。

  1) 利用信号量实线进程同步

  设有两个进程p1,p2 ,p2的Y语句需要等待p1中X语句的执行结果,说白了就是p2要等p1中x 语句执行完毕才能执行Y语句(Y→X )。

 1 semaphore s=0;  
 2 p1()  
 3 {  
 4   ...  
 5   x;//语句x  
 6   v(s);//通知进程p2,语句x已经执行完毕  
 7   ...  
 8 }  
 9 p2()  
10 {  
11   ...  
12   p(s);//当x未执行则陷入等待  
13   y;//此时x语句已执行完,可以执行y语句了  
14   ...  
15 }  

  2) 利用信号量实线进程互斥

  假设一次只能有一个进程进入临界区,则设置信号量S=1(即可用资源数为1)。假设此时有两个进程P1,P2(实际上可以有多个进程),那么实现临界资源互斥访问的算法如下。

 1 int semaphore s=1;  
 2 p1()  
 3 {  
 4    ...  
 5    p(s);  
 6    ...//临界区  
 7    v(s);  
 8    ...  
 9 }  
10 p2()  
11 {  
12    ...  
13    p(s);  
14    ...//临界区  
15    v(s);  
16    ...  
17 }  

   3) 利用信号量实线进程前驱关系

  下图给出了s1,s2,s3...s6六个进程间的依赖关系,为使六个进程得到有序的运行,需要对每个“依赖”用一个信号量来保证,为此我们针对这七个依赖设了七个信号量,分别是:a1,a2,b1,b2,c,d和e(均展示在图上)。

     

 1 s1()  
 2 {  
 3   ...  
 4   v(a1);v(a2);//告知s2、s3已执行完  
 5 }  
 6 s2()  
 7 {  
 8   ...  
 9   p(a1);//等待s1执行完  
10   ...  
11   v(b1);v(b2);//告知s4、s5已执行完  
12 }  
13 s3()  
14 {  
15   ...  
16   p(a2);//等待s1执行完  
17   ...  
18   v(c);//告知s6已执行完  
19 }  
20 s4()  
21 {  
22   ...  
23   p(b1);//等待s2执行完  
24   ...  
25   v(d);//告知s6已执行完  
26 }  
27 s5()  
28 {  
29   ...  
30   p(b2);//等待s1执行完  
31   ...  
32   v(e);//告知s6已执行完  
33 }  
34 s6()  
35 {  
36   ...  
37   p(c);p(d);p(e);//等待s3,s4,s5执行完  
38   ...  
39 }