1.某寺庙有小和尚、老和尚若干,有一水缸,由小和尚提水入缸供老和尚饮用。水缸可容10桶水,水取自同一井中。水井径窄,每次只能容一个桶取水。水桶总数为3个。每次入缸取水仅为1桶水,且不可同时进行。试给出有关从缸取水、入水的算法描述。
从井中取水并放入水缸是一个连续的动作,可视为一个进程;从缸中取水可视为另一个进程。设水井和水缸为临界资源,引入 well 和 vat:三个水桶无论是从井中取水还是将水倒入水缸都是一次一个,应该给它们一个信号量pail,抢不到水桶的进程只好等待。水缸满时,不可以再放水,设置 empty 信号量来控制入水量;水缸空时,不可以取水,设置 full 信号量来控制。本题需要设置5个信号量来进行控制:
semaphore well=1; //1个水井
semaphore vat=1; //1个水缸
pail=3; //3个水桶
empty=10; //水缸中的剩余空间能容纳的水的桶数,初值为10
full=0; //表示能从水缸中取走的水的桶数,初始水缸没水,处值为0
//小和尚
while(1){
P(empty); //检查水缸里能不能放水
P(pail); //能放水,则拿桶,桶-1
P(well); //到井中打水
从井中打水;
V(well); //打完水,释放“井”互斥资源
P(vat); //将水倒入缸中
将水倒入缸中;
V(vat); //倒完后,释放“水缸”互斥资源
V(full); //缸中水的桶数+1
V(pail); //使用完桶放回,桶+1
}
//老和尚
while(1){
P(full); //检查水缸中是否有水
P(pail); //拿桶装水
P(vat); //使用“水缸”互斥资源
从缸中取水;
V(vat); //释放互斥资源
V(empty); //水缸中的剩余空间+1
喝水;
V(pail); //把桶放回
}
2.如下图所示,三个合作进程P1,P2,P3,它们都需要通过同一设备输入各自的数据a,b,c,该输入设备必须互斥地使用,而且其第一个数据(a)必须由P1进程读取,第二个数据(b)必须由P2进程读取,第三个数据(c)必须由P3进程读取。然后,三个进程分别对输入数据进行下列计算:
最后,P1进程通过所连接的打印机将计算结果x,y,z的值打印出来。请用信号量实现它们的同步。
分析:
进程P1需要用到进程P1读取的a,进程P2读取的b:x=a+b
进程P2需要用到进程P1读取的a,进程P2读取的b:y=a*b
进程P3需要用到进程P2计算的结果y,进程P3读取的数据c,以及进程P1读取的数据a
所以:
P1进程在计算前,需要先确保已经输入了b,其他同理。
这里我们设置S1,S2,S3三个信号量,并将S1初值设为1,S2,S3初值设为0,这样就不用为输入设备专门设置互斥信号量了。但是这样设置就是默认三个进程中P1最先执行。信号量Sb,Sy,Sz分别表示是否已经输入b,以及y,z是否已经计算完成。Sb,Sy,Sz初值为0
P1(){
P(S1); //使用输入设备
输入数据a;
V(S2); //S2+1,表示接下来P2可以使用输入设备
P(Sb); //检查数据b有没有输入
x=a+b;
P(Sy); //检查y是否完成计算
P(Sz); //检查z是否完成计算
使用打印机打印出x,y,z的结果;
}
P2(){
P(S2);
输入数据b;
V(S3); //S3+1,表示接下来P3可以使用输入设备
V(Sb); //表示b已经输入,可以正常进行P(Sb)了
y=a*b;
V(Sy); //Sy已经计算完成,可以正常执行P(Sy)了
}
P3(){
P(P3);
输入数据c;
P(Sy); //检查y是否已经计算完成
z=y+c-a;
V(Sz); //可以执行P(Sz)
}
注意几点:
(1) 为什么P2,P3进程计算之前不需要P(S1)了,因为设置初值的时候我们把P1=1,P1最先执行,数据a最先输入,所以不需要检查数据a有没有输入
(2) 而P1执行时,就需要先检查b是否已经输入,即P(S2),所以进程实际执行的顺序:
① P1进程执行到P(Sb),发现Sb=0,不能继续往下执行
② 执行P2进程,P2进程V(Sb)
③ P1进程继续执行,直到P(Sz),Sz=0,堵塞
④ 执行P3进程,V(Sz)
⑤ P1继续执行
总之就是先V后P,一定要先V资源后,才能P资源
3.有桥如下图所示。车流方向如箭头所示。回答如下问题:
(1)假设桥上每次只能有一辆车行驶,试用信号灯的PV操作实现交通管理。
semaphore bridge=1;
NtoS(){
P(bridge);
通过桥;
V(bridge);
}
StoN(){
P(bridge);
通过桥;
V(bridge);
}
(2)假设桥上不允许两车交会,但允许同方向多辆车一次通过(桥上可有多辆同方向行驶的车)。试用信号灯的PV操作实现桥上的交通管理。
桥上可以同方向多车行驶,需要设置 bridge,还需要对同方向车辆计数。为了防止同方向计数中同时申请 bridge 造成同方向不可同时行车的问题,要对计数过程加以保护,因此设置信号量mutexSN和mutexNS。
int countSN=0; //从南向北的汽车数量
int countNS=0; //从北向南的汽车数量
semaphore mutexSN=1; //保护countSN
semaphore mutexNS=1; //保护countNS
semaphore bridge=1; //互斥信号量
StoN(){ //从南向北的汽车
P(mutexSN);
if(countSN==0)
P(bridge);
countSN++;
V(mutexSN);
过桥;
P(mutexSN);
countSN--;
if(countSN==0)
V(bridge);
V(mutexSN);
}
NtoS(){ //从北向南的汽车
P(mutexNS);
if(countNS==0)
P(bridge);
countNS++;
V(mutexNS);
过桥;
P(mutexNS);
countNS--;
if(countNS==0)
V(bridge);
V(mutexNS);
}
以StoN为例,若这里没有设置mutexSN,如果有多辆自南向北的车同时经过桥,那么都会检测到countSN=0,并且P(bridge),而bridge=1,只有1辆车能申请到bridge,其他车则不能经过桥,达不到题目的要求。
if(countSN==0)
P(bridge);
countSN++;
加入mutexSN:mutexSN=1,若有多辆自南向北的车同时经过桥,一辆车能成功执行P(mutexSN)并申请(bridge),成功记录该车后(countSN++),其他自南向北的车进程就会跳过if判断,不会被堵塞在P(bridge)。
P(mutexSN);
if(countSN==0)
P(bridge);
countSN++;
V(mutexSN);
4.假设一个录像厅有 1,2,3 三种不同的录像片可由观众选择放映,录像厅的放映规则如下:
1)任意时刻最多只能放映一种录像片,正在放映的录像片是自动循环放映的,最后一名观众主动离开时结束当前录像片的放映。
2)选择当前正在放映的录像片的观众可立即进入,允许同时有多位选择同一种录像片的观众同时观看,同时观看的观众数量不受限制。
3)等待观看其他录像片的观众按到达顺序排队,当一种新的录像片开始放映时,所有等待观看该录像片的观众可依次序进入录像厅同时观看。用一个进程代表一个观众要求:用信号量方法 PV操作实现,并给出信号量定义和初始值。
电影院一次只能放映一部影片,希望观看的观众可能有不同的爱好,但每次只能满足部分观众的需求,即希望观看另外两部影片的用户只能等待。分别为三部影片设置三个信号量s0,s1,s2初值分别为1、1、1。电影院一次只能放一部影片,因此需要互斥使用。由于观看影片的观众有多个,因此必须分别设置三个计数器(初值都是0),用来统计观众个数。当然,计数器是个共享变量,需要互斥使用。
semaphore s=1,s0= 1,s1= 1,s2= 1; //s保证了一次只放一部影片
int count0=0,count1=0,count2=0; //看第一部影片的观众
process videoshow1 {
P(s0);//设置P(s0)/V(s0),保证了计数的互斥性,防止同时申请s信号量的观众,不能同时观看影片
count0=count0+1;
if(count0==1)//如果是第1位观看第1部影片的观众,则为他分配互斥信号量s,后面来的观众就不需要P(s)了,因为已经在放映第1部影片了
P(s);
V(s0);
看影片;
P(s0) ;count0=count0-1;
if(count0==0) //没人看了,就结束放映
V(s); //释放互斥信号量s,这样其他影片就可以放映了
V(s0);}
process videoshow2 {
P(s1);
count1=count1+1;
if(count1==1)
P(s);
V(s1);
看影片;
P(s1) ;count1=count1-1;
if(count1==0) //没人看了,就结束放映
V(s);
V(s1);}
process videoshow3 {
P(s2);
count2=count2+1;
if(count2==1)
P(s);
V(s2);
看影片;
P(s2) ;count2=count2-1;
if(count2==0) //没人看了,就结束放映
V(s);
V(s2);}
提示:这道题和第3题思路是类似的
5.设公共汽车上驾驶员和售票员的活动分别如下图所示。驾驶员的活动:启动车辆,正常行车,到站停车;售票员的活动:关车门,售票,开车门。在汽车不断地到站、停车、行驶的过程中,这两个活动有什么同步关系?用信号量和P,V操作实现它们的同步。
在汽车行驶过程中,驾驶员活动与售票员活动之间的同步关系为:售票员关车门后,向驾驶员发开车信号,驾驶员接到开车信号后启动车辆,在汽车正常行驶过程中售票员售票,到站时驾驶员停车,售票员在车停后开门让乘客上下车。因此,驾驶员启动车辆的动作必须与售票员关车门的动作同步;售票员开车门的动作也必须与驾驶员停车同步。应设置两个信号量S1,S2:
S1表示是否允许驾驶员启动汽车(初值为0);S2表示是否允许售票员开门(初值为0)。
semaphore S1=0,S2=0;
Procedure driver
{
while(1){
P(S1); //检查是否允许驾驶员启动汽车,即P(S1)=1Start; //启动汽车
Driving;
Stop;
V(S2); //停车后允许售票员开门}
}
Procedure Conductor
{
while(1){
关车门;
V(s1); //允许驾驶员开车
售票;
P(s2); //检查是否允许售票员开门,即P(S2)=1开车门;
上下乘客;}
}