操作系统原理之经典PV问题
本文记录9道PV问题的解,不保证正确,仅供参考,,
1、 有一个仓库,可以存放 A 和 B 两种产品,仓库的存储空间足够大,但要求:
( 1)一次只能存入一种产品( A 或 B);
( 2) -N < (A 产品数量-B 产品数量) < M。
其中, N 和 M 是正整数。试用“存放 A”和“存放 B”以及 P、 V 操作描述产品 A 与
产品 B 的入库过程。
1 Semaphore mutex = 1; //互斥信号量 2 Semaphore a = M-1 ; //存放A的资源信号量,初值为M-1 3 Semaphore b = N-1; //存放B的资源信号量,初值为N-1 4 存放 A: 5 { 6 while(true) 7 { 8 Get A; 9 P(&a); 10 P(&mutex); 11 Put A; 12 V(&mutex); 13 V(&b); 14 } 15 } 16 存放B: 17 { 18 while(true) 19 { 20 Get B; 21 P(&b); 22 P(&mutex); 23 Put B; 24 V(&mutex); 25 V(&a); 26 } 27 }
2、 桌子上有一只盘子,最多可容纳两个水果,每次只能放入或取出一个水果。爸爸专向盘
子放苹果( apple),妈妈专向盘子中放桔子( orange);两个儿子专等吃盘子中的桔子,
两个女儿专等吃盘子中的苹果。请用 P、 V 操作来实现爸爸、妈妈、儿子、女儿之间的
同步与互斥关系。
1 Semaphore mutex = 1; //互斥信号量, 其初值为1 2 Semaphore empty = 2; //记录允许向盘子中放入水果的个数,初值为2 3 Semaphore orange = 0; //盘子中已放入的苹果的个数,初值为0 4 Semaphore apple = 0; //盘子中已放入的桔子的个数,初值为0 5 main() 6 { 7 Cobegin 8 { 9 father //父亲进程 10 { 11 while (true) 12 { 13 P(empty); //减少盘中可放入的水果数 14 P(mutex); //申请向盘中取、放水果 15 向盘中放苹果; 16 V(mutex); //允许向盘中取、放水果 17 V(apple); //递增盘中的苹果数 18 } 19 } 20 mother //母亲进程 21 { 22 while (true) 23 { 24 P(empty); //减少盘中可放入的水果数 25 P(mutex); //申请向盘中取、放水果 26 向盘中放桔子; 27 V(mutex); //允许向盘中取、放水果 28 V(orange); //递增盘中的桔子数 29 } 30 } 31 daughteri(i=1,2) //两女儿进程 32 { 33 while (true) 34 { 35 P(apple); //减少盘中苹果数 36 P(mutex); //申请向盘中取、放水果 37 取盘中苹果; 38 V(mutex); //允许向盘中取、放水果 39 V(empty); //递增盘中可放入的水果数 40 } 41 } 42 sonj(j=1,2) //两儿子进程 43 { 44 while (true) 45 { 46 P(orange); //减少盘中桔子数 47 P(mutex); //申请向盘中取、放水果 48 取盘中桔子; 49 V(mutex); //允许向盘中取、放水果 50 V(empty); //递增盘中可放入的水果数 51 } 52 } 53 } 54 Coend 55 }
3、 有一个理发师,一把理发椅和 N 把供等候理发的顾客坐的椅子。如果没有顾客,则理发
师便在理发师椅子上睡觉;当一个顾客到来时,必须唤醒理发师进行理发;如果理发师
正在理发时又有顾客来到,则如果有空椅子可坐,他就坐下来等,如果没有空椅子,他
就离开。为理发师和顾客各编一段程序(伪代码)描述他们的行为,要求不能带有竞争
条件。
1 Semaphore mutex = 1; //互斥信号量,初值为1. 2 Semaphore Wait = 0; //等待服务的顾客数 3 Semaphore barbers= 0; //等待顾客的理发师数 4 Int custNum = 0; //等待的顾客(还没理发的) 5 6 Costumer() 7 { 8 while(true) 9 { 10 P(mutex); //申请理发 11 if(custNum>0) 12 { 13 if(custNum<N) //若等待人数小于N 14 { 15 V(mutex); //释放进程等待 16 CustNum++; //增加等待人数 17 } 18 else //若等待人数超过N 19 { 20 V(mutex); //释放进程等待 21 离开; 22 } 23 } 24 else //若目前无人等待 25 { 26 V(mutex); //释放进程等待 27 V(barbers); //如果必要的话,唤醒理发师 28 理发; 29 离开; 30 P(mutex); //要求进程等待 31 custNum--; //顾客人数减1 32 V(mutex); //释放进程等待 33 V(wait); //等待人数减1 34 } 35 } 36 } 37 38 Barber() 39 { 40 while(true) 41 { 42 P(mutex); //要求进程等待 43 if(custNum ==0) //目前无顾客 44 { 45 V(mutex); //释放进程等待 46 P(barbers); //理发师睡觉 47 } 48 else 49 { 50 V(mutex); //释放进程等待 51 理发; 52 } 53 } 54 }
4、 吸烟者问题。三个吸烟者在一间房间内,还有一个香烟供应者。为了制造并抽掉香烟,
每个吸烟者需要三样东西:烟草、纸和火柴。供应者有丰富的货物提供。三个吸烟者中,
第一个有自己的烟草,第二个有自己的纸,第三个有自己的火柴。供应者将两样东西放
在桌子上,允许一个吸烟者进行对健康不利的吸烟。当吸烟者完成吸烟后唤醒供应者,
供应者再放两样东西(随机地)在桌面上,然后唤醒另一个吸烟者。试为吸烟者和供应
者编写程序解决问题。
1 Semaphore S = 1; //供应者 2 Semaphore S1,S2,S3; //三个吸烟者 3 S1 = S2 = S3 = 0; 4 bool flag1,flag2,fiag3; //三种吸烟原料 5 fiag1=flag2=flag3=true; 6 7 Apply() //供应者 8 { 9 While(true) 10 { 11 P(S); 12 取两样香烟原料放桌上,由flagi标记; 13 if (flag2 && flag3) //供纸和火柴 14 { 15 V(S1); //唤醒吸烟者一 16 } 17 else if(flag1 && fiag3) //供烟草和火柴 18 { 19 V(S2); //唤醒吸烟者二 20 } 21 else //供烟草和纸 22 { 23 V(S3); //唤醒吸烟者三 24 } 25 } 26 } 27 28 Smoker1() //吸烟者一 29 { 30 While(true) 31 { 32 P(S1); 33 取原料; 34 做香烟; 35 V(S); //唤醒供应者 36 吸香烟; 37 } 38 } 39 40 smoker2() //吸烟者二 41 { 42 While(true) 43 { 44 P(S2); 45 取原料; 46 做香烟; 47 V(S); //唤醒供应者 48 吸香烟; 49 } 50 } 51 52 Smoker3() //吸烟者三 53 { 54 While(true) 55 { 56 P(S3); 57 取原料; 58 做香烟; 59 V(S); //唤醒供应者 60 吸香烟; 61 } 62 }
5、 面包师问题。面包师有很多面包和蛋糕,由 n 个销售人员销售。每个顾客进店后先取
一个号,并且等着叫号。当一个销售人员空闲下来,就叫下一个号。请分别编写销售人
员和顾客进程的程序。
1 Semaphore buyer= 0; //顾客人数 2 Semaphore seller = n; //销售人员数 3 Semaphore mutex_s = 1; //用于销售人员的互斥信号量 4 Semaphore mutex_b = 1; //用于顾客的互斥信号量 5 int count_s = 0; //记录取号的值 6 int count_b = 0; //记录叫号的值 7 8 void Buy() //顾客进程 9 { 10 进店; 11 P(mutex_b); //取号 12 count_b++; 13 V(mutex_b); 14 V(buyer); 15 P(seller); //等待叫号 16 买面包; 17 离开 18 } 19 20 void Sell() 21 { 22 while(true) 23 { 24 P(buyer); 25 P(mutex_s); //叫号 26 count_s++; 27 叫编号为count_s的顾客; 28 V(mutex_s); 29 V(seller); 30 } 31 }
6、 桌上有一空盘,运行存放一只水果,爸爸可向盘中放苹果,也可放桔子,儿子专等吃盘
中的桔子,女儿专等吃盘中的苹果。规定当盘中空时一次只能放一个水果供吃者取用,
用 P,V 原语实现爸爸儿子和女儿 3 个并发进程的同步。
1 Semaphore S = 1; //S 表示盘子是否为空; 2 Semaphore Sa = 0; //Sa 表示盘中是否有苹果; 3 Semaphore Sb = 0; //Sb 表示盘中是否有桔子; 4 5 Father() //父亲进程 6 { 7 while(TRUE) 8 { 9 P(S); 10 将水果放入盘中; 11 if (放入的是桔子) 12 V(Sb); 13 else 14 V(Sa); 15 } 16 } 17 18 Son() //儿子进程 19 { 20 while(TRUE) 21 { 22 P(Sb); 23 从盘中取出桔子; 24 V(S); 25 吃桔子; 26 } 27 } 28 29 Daughter() //女儿进程 30 { 31 while(TRUE) 32 { 33 P(Sa); 34 从盘中取出苹果; 35 V(S); 36 吃苹果; 37 } 38 }
7、 写者优先的读者--写者问题。读者-写者问题为数据库访问建立了一个模型。例如,一
个系统,其中有许多竞争的进程试图读写其中的数据,多个进程同时读是可以接受的,但如
果一个进程正在更新数据库,则所有的其他进程都不能访问数据库,即使读操作也不行。
写者优先是指当一个写者到达时,将阻止其后面的读者进入数据库,直到其离开为止。
1 Semaphore Mut1, Mut2, Wmutex, Fmutex; //互斥信号量 2 int Rcount, Wcount; //读写者人数 3 Mut1 = Mut2 = WMutex = Fmutex = 1; 4 Rcount = Wcount = 0; 5 6 Writer() //写者进程 7 { 8 While(true) 9 { 10 P(Mut1); 11 Wcount=Wcount+1; 12 If (Wcount==1) 13 { 14 P(Fmutex); //如有读者,写者阻塞在此处 15 } 16 V(Mut1); 17 P(WMutex); 18 写; 19 V(Wmutex); 20 P(Mut1); 21 Wcount=Wcount-1; 22 If (Wcount==0) 23 { 24 V(Fmutex); 25 } 26 V(Mut1); 27 } 28 } 29 30 Reader() //读者进程 31 { 32 While(true) 33 { 34 P(Mut2); 35 Rcount=Rcount+1; 36 If (Rcount==1) 37 { 38 P(Fmutex); 39 } 40 V(Mut2); 41 读; 42 P(Mut2); 43 Rcount=Rcount-1; 44 If (Rcount==0) 45 { 46 V(Fmutex); 47 } 48 V(Mut2); 49 } 50 }
8、 在天津大学与南开大学之间有一条弯曲的小路,这条路上每次每个方向上只允许一辆自
行车通过。但其中有一个小的安全岛 M,同时允许两辆自行车停留,可供两辆自行车已
从两端进入小路的情况下错车使用。如图所示。
下面的算法可以使来往的自行车均可顺利通过。其中使用了 4 个信号量, T 代表天大路
口资源, S 代表南开路口资源, L 代表从天大到安全岛一段路的资源, K 代表从南开到
安全岛一段路的资源。程序如下,请在空白位置处填写适当的 PV 操作语句,每处空白
可能包含若干个 PV 操作语句。
1 begin 2 t:=1;s:=1;l:=1;k:=1; 3 cobegin 4 从天大到南开的进程 5 begin 6 ______(1)______ 7 通过 L 路段; 8 进入安全岛 M; 9 ______(2)______ 10 通过 K 路段 11 ______(3)______ 12 end 13 从南开到天大的进程 14 begin 15 略,与“从天大到南开的进程”相反。 16 end 17 coend 18 end
解答:
(1) P(t); P(l);
(2) V(l); P(k);
(3) V(k); V(t);
9、 三个进程 P1、 P2、 P3 互斥使用一个包含 N(N>0)个单元的缓冲区。 P1 每次用 produce()
生成一个正整数并用 put()送入缓冲区某一空单元中;P2 每次用 getodd()从该缓冲区中
取出一个奇数并用 countodd()统计奇数个数;P3 每次用 geteven()从该缓冲区中取出一
个偶数并用 counteven()统计偶数个数。请用信号量机制实现这三个进程的同步与互斥活
动,并说明所定义信号量的含义。要求用伪代码描述。
1 P1() 2 { 3 While(true) 4 { 5 X = produce(); //生成一个数 6 P(empty); //是否有空单元格 7 P(mutex); //进入临界区 8 Put(); 9 if(X%2 == 0) 10 V(s2); //如果是偶数,向P3发出信号 11 else 12 V(s1); //如果是奇数,向P2发出信号 13 V(mutex); //离开临界区,释放互斥信号量 14 } 15 } 16 17 P2() 18 { 19 While(true) 20 { 21 P(s1); //收到P1发送来的信号,已产生奇数 22 P(mutex); //进入临界区 23 getodd(); 24 countodd():=countodd()+1; 25 V(mutex); 26 V(empty); //离开临界区,释放互斥信号量 27 } 28 } 29 30 P3() 31 { 32 While(true) 33 { 34 P(s2) //收到P1发送来的信号,已产生偶数 35 P(mutex); //进入临界区 36 geteven(); 37 counteven():=counteven()+1; 38 V(mutex); 39 V(empty); //离开临界区,释放互斥信号量 40 } 41 }