信号量(前驱关系控制)
10
资资
开始于 2016-03-09 11:11
238 100 0
已截止

任务尚未发布或者你没有权限查看任务内容。

任务讨论
设有两个并发执行的进程P1和P2。P1中有语句S1;P2中有语句S2。我们希望在S1执行后再执行S2。为实现这种前驱关系,只需使进程P1和P2共 享一个公用信号量S,并赋予其初值为0,将signal(S)操作放在语句S1后面,而在S2语句前面插入wait(S)操作,即在进程P1中,用 S1;signal(S);在进程P2中,用wait(S);S2;

由于S被初始化为0,这样,若P2先执行必定阻塞,只有在进程P1执行完S1;signal(S);操作后使S增为1时,P2进程方能成功执行语句S2。

设有两个进程p1,p2与 p3,设置公有的信号量s1,s2其初始值为0,想控制进程使其执行顺序为p1,p2,p3。则可以使用如下代码:

p1(){代码段;signal(s1);}

p2(){wait(s1);代码段;signal(s2);}

p3(){wait(s2);代码段;}

main(){

    semaphore s1,s2;

    s1.value=s2.value=0;//赋初值为0

    cobegin//并发控制代码

       p1();

      p2();

      p3();

    coend

}

因为s1与s2中的value初始值为0,所以p2与p3都无法先于p1执行,只有p1执行后,将s1++,才能使p2执行同时p3无法执行,只有p2执行后s2++,p3才能执行,这及时利用记录信号量控制进程之间的前驱关系。



如图S1,S2,S3,...,S6是最简单的程序段(只有一条语句)。为使各程序段能正确执行,应设置若干个初始值为"0"的信号量。如为保证S1→S2,S1→S3的前趋关系,应分别设置信号量a和b,同样,为了保证S2→S4,S2→S5,S3→S6,S4→S6和S5→S6,应设置信号量c,d,e,f,g。代码框架描述如下:

p1(){S1;signal(a);signal(b);}

p2(){wait(a);S2;signal(c);signal(d);}

p3(){wait(b);S3;signal(e);} 

p4(){wait(c);S4;signal(f);} 

p5(){wait(d);S5;signal(g);} 

p6(){wait(e);wait(f);wait(g);S6;}

 

main(){

   semaphore a,b,c,d,e,f,g;

   a.value=b.value=c.value=0;

   d.value=e.value=0;

   f.value=g.value=0;

   cobegin

      p1();p2();p3();p4();p5();p6();

   coend
}

首先,P操作,首先将S.value减1,表示该进程需要一个临界资源,如果S.value<0,那么说明原来的S.value <= 0,即已经没有资源可用了,于是将进程阻塞到与信号量S相关的阻塞队列中去,如果S.value<0,那么|S.value|其实就表示阻塞队列的长度,即等待使用资源的进程数量。然后,V操作:首先S.value加1,表示释放一个资源,如果S.value <= 0,那么说明原来的S.value < 0,阻塞队列中是由进程的,于是唤醒该队列中的一个进程。那么,为什么S.value > 0时不唤醒进程呢,很简单,因为阻塞队列中没有进程了。

P操作相当于“等待一个信号”,而V操作相当于“发送一个信号”,在实现同步过程中,V操作相当于发送一个信号说合作者已经完成了某项任务,在实现互斥过程中,V操作相当于发送一个信号说临界资源可用了。实际上,在实现互斥时,P,V操作相当于申请资源和释放资源。

我们将信号量初值设置为1时通常可实现互斥,因为信号量表示资源可用数目,互斥信号量保证只有一个进程访问临界资源,相当于只有一个访问权可用。设置为0或者N时可以用来实现同步。