3.在某超市里有一个收银员,且同时最多允许有n个顾客购物,我们可以将顾客和收银员看成是两类不同的进程,且工作流程如下图所示。为了利用PV操作正确地协调这两类进程之间的工作,设置了三个信号量S1、S2和Sn,且初值分别为0、0和n。这样图中的a应填写__(1)__,图中的b1、b2应分别填写__(2)__,图中的c1、c2应分别填写__(3)__。
500){this.resized=true;this.style.width=500;}" resized="true">
(1) A. P(S1) B.P(S2) C.P(Sn) D.P(Sn)、P(S1)
(2) A.P(Sn)、V(S2) B.P(Sn)、V(S1) C.P(S2)、V(S1) D.V(S1)、P(S2)
(3) A.P(S1)、V(S2) B.P(Sn)、V(S1) C.P(S2)、V(S1) D. V(S1)、 P(S2)
答案:(1)C (2)D (3)A
解析:这是一道考查PV操作的题,所以首先得弄清楚那些地方需要互斥、那些地方需要同步。题目中给出了两类进程:顾客进程与收银元进程,由于超市是顾客进程之间的公有资源,而且超市里限制最多允许有n个顾客购物,所以要设置一个公有信号量Sn,初值是n,顾客进程在进入超市时要执行P(Sn),离开超市时要执行V(Sn)操作。顾客购物后要到收银员处付款,因此顾客进程与收银员进程之间是同步的关系,一次只允许一个顾客进程付款,整个超市只有一个收银员进程收费,所以需要为顾客进程设置一个私有信号量S2,为收银员进程设置一个私有信号量S1,由于开始时没有顾客去付款,收银员也没有收费,所以S1和S2的初值为0。当有顾客买完东西去付款时执行V(S1),通知收银员进程有顾客付款,此时收银员进程执行P(S1)操作后就可进入收费,收费完成后收银元进程执行V(S2),以通知顾客收费完毕,此时顾客执行P(S2)就可离开收银台,在离开超市时需执行V(Sn),释放资源。
复习提示:PV操作在操作系统中处于很重要得地位,要想合适的运用PV操作,必须很好的理解进程之间的互斥与同步,即那些进程之间是互斥的,那些进程之间是同步的。
2005年上半年程序员试题
●某系统中有一个缓冲区,进程P1不断地生产产品送入缓冲区,进程P2不断地从缓冲区取产品消费。假设该缓冲区只能容纳一个产品。进程P1与P2的同步模型如下图所示:
(这个图就是教程中常见的那个图)
P1 P2
__| __|
| 生产一个产品 | P(S2)
| P(S1) | 从缓冲区取一个产品
| 产品送缓冲区 | V(S1)
| V(S2) | 消费
|__| |__|
为此,应设信号量S1的初值为__(18)__,信号量S2的初值为__(19)__。
(18) A.-2 B.-1 C.0 D.1
(19) A.-2 B.-1 C.0 D.1
答案:(18)D (19)C
分析:
资源S是这个资源初始状态拥有的数目,也就是没有任何操作,刚开始的时候资源的可用数。
简单的例子,一个盘子可以放8个苹果,一次只能一个人拿一个苹果或者放一个苹果,则设置两个资源S1、S2分别表示盘子中苹果的数量和取放苹果的许可,则S1初始值为8,S2为1。
以下一定要记住:
P操作
S = S-1
S<0 阻塞
V操作
S= S+1
S 〈=0 唤醒
S1、S2分别是P1、P2对缓冲区操作的开关,S1=1表示初始状态P1进程可以对缓冲区进行操作,而对于S2=0正好阻止了P2进程对缓冲区的操作!在刚开始的时候缓冲区为空,其允许P1在其中放入产品,但不能让P2取出产品,所以才产生这样的结果
P一次什么什么就减一个。如果你P的玩意是0.那P下面的东西就不开工了。
V 一次什么就加一次
这个同步有s1 s2.
s1肯定是为1的。缓冲区可以放几个东西就应该是几.
你P了p1 一次以后。 代表向缓冲区里放了东西。s1 = 0了。表示缓冲区不能放东西了。进程时并行了。假设这句执行完了后跳到第二个程序中去。是p(s2) 刚肯定不行。所以s2一定要为初始要为0. 要等待第一个放进缓冲区的事做完后V(s2)把s2标志位搞醒
●某仓库有两名发货员,一名审核员。当顾客提货时,只要发货员空闲,允许顾客进入仓库提货,顾客离开时,审核员检验顾客提货是否正确。其工作流程如下图所示。为了利用PV操作正确地协调他们之间的工作,设置了两个信号量S1和S2,且S1的初值为2,S2的初值为1。图中的a应填写____(25)___;图中的b、c和d应分别填写____(26)____。
500){this.resized=true;this.style.width=500;}">
供选择的答案:
(25)A.P(S1) B.P(S2) C.V(S1) D.V(S2)
(26)A.P(S2)、V(S2)和V(S1) B.P(S1)、V(S1)和V(S2)
C.V(S1)、P(S2)和V(S2) D.V(S2)、P(S1)和V(S1)
分析:
顾客来了,要看看是否有发货员.即发货员资源是否存在.
所以用P(S1) 若S1>0表示,存在(无论多少)
若S1<=0表示,不存在,进程阻塞.
提完货.这说明,肯定用发货员了.肯定还有人等着提货.这时,应该释放发货员.
所以用V(S1)
然后,要审货.
可能有人正在审呢,所以用P(S2)意思和上面相同.
审完货.要释放,可能有人正等着审呢.所以用V(S2)释放审货员.
完毕.
PV原语实现进程间互斥与同步
PV原语的含义
P操作和V操作是不可中断的程序段,称为原语。PV原语及信号量的概念都是由荷兰科学家E.W.Dijkstra提出的。信号量sem是一整数,sem大于等于零时代表可供并发进程使用的资源实体数,但sem小于零时则表示正在等待使用临界区的进程数。
P原语操作的动作是:
(1)sem减1;
(2)若sem减1后仍大于或等于零,则进程继续执行;
(3)若sem减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。
V原语操作的动作是:
(1)sem加1;
(2)若相加结果大于零,则进程继续执行;
(3)若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度。
PV操作对于每一个进程来说,都只能进行一次,而且必须成对使用。在PV原语执行期间不允许有中断的发生。
用PV原语实现进程的互斥
由于用于互斥的信号量sem与所有的并发进程有关,所以称之为公有信号量。公有信号量的值反映了公有资源的数量。只要把临界区置于P(sem)和V(sem)之间,即可实现进程间的互斥。就象火车中的每节车厢只有一个卫生间,该车厢的所有旅客共享这个公有资源:卫生间,所以旅客间必须互斥进入卫生间,只要把卫生间放在P(sem)和V(sem)之间,就可以到达互斥的效果。以下例子说明进程的互斥实现。
例1
生产围棋的工人不小心把相等数量的黑子和白子混装载一个箱子里,现要用自动分拣系统把黑子和白子分开,该系统由两个并发执行的进程组成,功能如下:
(1)进程A专门拣黑子,进程B专门拣白子;
(2)每个进程每次只拣一个子,当一个进程在拣子时不允许另一个进程去拣子;
分析:
第一步:确定进程间的关系。由功能(2)可知进程之间是互斥的关系。
第二步:确定信号量及其值。由于进程A和进程B要互斥进入箱子去拣棋子,箱子是两个进程的公有资源,所以设置一个信号量s,其值取决于公有资源的数目,由于箱子只有一个,s的初值就设为1。
实现:
begin
s:semaphore;
s:=1;
cobegin
process A
begin
L1: P(s);
拣黑子;
V(s);
goto L1;
end;
process B
begin
L2:P(s);
拣白子;
V(s);
goto L2;
end;
coend;
end;
判断进程间是否互斥,关键是看进程间是否共享某一公有资源,一个公有资源与一个信号量相对应。确定信号量的值是一个关键点,它代表了可用资源实体数。如下实例:
例2
某车站售票厅,任何时刻最多可容纳20名购票者进入,当售票厅中少于20名购票者时,厅外的购票者可立即进入,否则需要在外面等待。每个购票者可看成一个进程。
分析:第一步:确定进程间的关系。售票厅是各进程共享的公有资源,当售票厅中多于20名购票者时,厅外的购票者需要在外面等待。所以进程间是互斥的关系。第二步:确定信号量及其值。只有一个公有资源:售票厅,所以设置一个信号量s。售票厅最多容纳20个进程,即可用资源实体数为20,s的初值就设为20。
实现:
begin
s:semaphore;
s:=20;
cobegin
process PI(I=1,2,……)
begin P(s);
进入售票厅;
购票;
退出;
V(s);
end;
coend
当购票者进入售票厅前要执行P(s)操作,执行后若s大于或等于零,说明售票厅的人数还未满可进入。执行后若s小于零,则说明售票厅的人数已满不能进入。这个实现中同时最多允许20个进程进入售票厅购票,其余进程只能等待。
用PV原语实现进程的同步
与进程互斥不同,进程同步时的信号量只与制约进程及被制约进程有关而不是与整组并发进程有关,所以称该信号量为私有信号量。利用PV原语实现进程同步的方法是:首先判断进程间的关系为同步的,且为各并发进程设置私有信号量,然后为私有信号量赋初值,最后利用PV原语和私有信号量规定各进程的执行顺序。下面我们将例1增添一个条件,使其成为进程间是同步的。
例3
在例1的基础之上再添加一个功能:
(3)当一个进程拣了一个棋子(黑子或白子)以后,必让另一个进程拣一个棋子(黑子或白子)。
分析:
第一步:确定进程间的关系。由功能(1)(2)(3)可知,进程间的关系为同步关系。第二步:确定信号量及其值。进程A和B共享箱子这个公有资源,但规定两个进程必须轮流去取不同色的棋子,因而相互间要互通消息。对于进程A可设置一个私有信号量s1,该私有信号量用于判断进程A是否能去拣黑子,初值为1。对于进程B同样设置一个私有信号量s2,该私有信号量用于判断进程B是否能去拣白子,初值为0。当然你也可以设置s1初值为0,s2初值为1。
实现:
begin
s1,s2:semaphore;
s1:=1;s2:=0;
cobegin
process A
begin
L1: P(s1);
拣黑子;
V(s2);
goto L1;
end;
process B
begin
L2:P(s2);
拣白子;
V(s1);
goto L2;
end;
coend;
end;
另外一个问题就是P原语是不是一定在V原语的前面?回答是否定的。下面看一个例子。
例4
设在公共汽车上,司机和售票员的活动分别是:司机:启动车辆,正常行车,到站停车。售票员:上乘客,关车门,售票,开车门,下乘客。用PV操作对其控制。
分析:
第一步:确定进程间的关系。司机到站停车后,售票员方可工作。同样,售票员关车门后,司机才能工作。所以司机与售票员之间是一种同步关系。
第二步:确定信号量及其值。由于司机与售票员之间要互通消息,司机进程设置一个私有信号量run,用于判断司机能否进行工作,初值为0。售票员进程设置一个私有信号量stop,用于判断是否停车,售票员是否能够开车门,初值为0。
实现:
begin stop ,run:semaphore
stop:=0;run:=0;
cobegin
driver: begin
L1: P(run);
启动车辆;
正常行车;
到站停车;
V(stop);
goto L1;
end;
conductor:begin
L2:上乘客;
关车门;
V(run);
售票;
P(stop);
开车门;
下乘客;
goto L2;
end;
coend;
end;
用PV操作还可以实现进程同步与互斥的混合问题,典型的如:多个生产者和多个消费者共享容量为n的缓存区。这个例子在很多书中都有介绍,在这里就不说了。