所有有可能被并发访问的信号量 必须互斥进行。
解题步骤:
【例】
某工厂有两个生产车间和一个装配车间,两个生产车间分别生产A、B两种零件,装配车间的任务是把A、B两种零件组装成产品。两个生产车间每生产一个零件后,都要分别把它们送到装配车间的货架F1、F2上。F1存放零件A,F2存放零件B,F1和F2的容量均可存放10个零件。装配工人每次从货架上取一个零件A和一个零件B后组装成产品。请用P、V操作进行正确管理。
【解析】
1、三类进程
2、梳理同步关系
3、梳理互斥关系:货架互斥
4、定义信号量
- semaphore F1 = 10; //F1货架的空闲位置
- semaphore F2 = 10; //F2货架的空闲位置
- semaphore full1 = 0; //F1货架的商品A数量
- semaphore full2 = 0; //F2货架的商品B数量
- semaphore m1 = 1; //互斥访问货架F1
- semaphore m2 = 1; //互斥访问货架F2
-
- P1(){ //生产车间A
- while(1){
- 生产A零件;
- P(F1); //申请F1货架空闲位置
- P(m1); //互斥访问F1货架
- A放到货架F1上;
- V(m1); //释放货架F1
- V(full1); //货架F1上商品A数量加1
- }
- }
-
- P2(){ //生产车间B
- while(1){
- 生产B零件;
- P(F2);
- P(m2);
- B放到货架F2上;
- V(m2);
- V(full2);
- }
- }
-
- C(){ //装配车间
- while(1){
- P(full1);
- P(m1);
- 从F1货架取得A商品;
- V(m1);
- V(F1);
- P(full2);
- P(m2);
- 从F2货架取得B商品;
- V(m2);
- V(F2);
- 组装产品;
- }
- }
【2014年统考】
系统中有多个生产者进程和多个消费者进程,共享一个能存放1000件产品的环形缓冲区(初始为空)。当缓冲区未满时,生产者进程可以放入其生产的一件产品,否则等待;当缓冲区未空时,消费者进程可以从缓冲区取走一件产品,否则等待。
要求一个消费者进程从缓冲区连续取出10件产品后,其他消费者进程才可以取产品。请使用信号量P,V(或wait(),signal())操作实现进程间的互斥与同步,要求写出完整的过程,并说明所用信号量的含义和初值。
【解析】
1、两类进程
2、分析同步和互斥关系
如果暂未取出十个 将会卡在 for循环或者10个full中。但是!
注意此处:连续取出10个必须一气呵成,否则将会有其他进程P走属于你的full。
3、定义信号量
- semaphore empty = 1000; //缓冲区空位个数
- semaphore full = 0; //缓冲区产品个数
- semaphore m1 = 1; //互斥访问缓冲区
- semaphore m2 = 1; //控制进程单次互斥访问缓冲区(实现连续取10次)
-
- producer(){
- while(1){
- 生产一个产品;
- P(empty); //占用一个空位
- P(m1); //互斥访问缓冲区
- 商品放入缓冲区;
- V(m1); //互斥访问缓冲区
- V(full); //产品数量+1
- }
- }
-
- consumer(){
- while(1){
- P(m2); //连续取10次
- for(int i=0;i<10;i++){
- P(full); //有商品
- P(m1); //互斥访问缓冲区
- 取出一个商品;
- V(m1); //互斥访问缓冲区
- V(empty); //腾出一个空位
- 消费这件产品;
- }
- V(m2);
- }
【例题】
某寺庙有小和尚、老和尚若干,有一水缸,由小和尚提水入缸供老和尚饮用。水缸可容10桶水,水取自同一井中。水井径窄,每次只能容一个桶取水。水桶总数为3个。每次入缸取水仅为1桶水,且不可同时进行。试给出有关从缸取水、入水的算法描述。
【解析】
1、两类进程
2、
先看老和尚:喝水的老和尚要桶 P(tong) ,也要缸里的水 P(full)。再加入互斥条件。
再看小和尚:打水的小和尚要桶 P(tong),要井 P(jing) ,要缸的空间 P(empty)
3、定义信号量
- semaphore tong = 3; //三个桶
- semaphore full = 0; //缸中有几桶水
- semaphore empty = 10; //水缸中剩余可容纳水的桶数
- semaphore jing = 1; //小和尚互斥访问水井
- semaphore gang = 1; //小和尚、老和尚互斥访问水缸
4、检查是否可能出现死锁,连续的P操作。通常可以调换执行顺序解决。
上述代码中,若有三个老和尚上来就把三个桶拿了,那小和尚就会一直请求桶,老和尚一直请求水,出现死锁。
所以调整一下:老和尚要拿桶,你得先有水。小和尚要拿桶,你得先有井。
通常要使用一个变量记录等待顾客的人数。且对此变量的访问互斥进行。
【例题】
理发店理有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子。如果没有顾客,理发师便在理发椅上睡觉,一个顾客到来时,顾客必须叫醒理发师,如果理发师正在理发时又有顾客来到,则如果有空椅子可坐,就坐下来等待,否则就离开。
【解析】
1、两类进程
【例题】
面包师有很多面包,由n个销售人员推销。每个顾客进店后取一个号,并且等待叫号,当一个销售人员空闲下来时,就叫下一个号。试设计一个使销售人员和顾客同步的算法。
【法一】
【法二】
- P(){
- if(count==0)
- P(source); //第一个为后面的兄弟们抢占资源,上锁
- count++;
- 使用source;
- count--;
- if(count==0) //最后一个解锁
- V(source);
- }
【例题】
【解析】
(1)
(2)
1、两类进程:需要记录各类进程中各有几个进程正在使用 临界资源
2、异类互斥,第一个人上锁,最后一个解锁。
- P1(){
- if(count1==0)
- P(bridge); //第一个为后面的兄弟们抢占大桥,上锁
- count1++;
- 过桥; //使用资源
- count1--;
- if(count1==0) //最后一个解锁
- V(bridge);
- }
3、定义信号量
【例题】
一个主修人类学、辅修计算机科学的学生参加了一个研究课题,调查是否可以教会非洲狒狒理解死锁。他找到一处很深的峡谷,在上边固定了一根横跨峡谷的绳索,这样狒狒就可以攀住绳索越过峡谷。
同一时刻,只要朝着相同的方向就可以有几只狒狒通过。但如果向东和向西的狒狒同时攀在绳索上那么会产生死锁(狒狒会被卡在中间),由于它们无法在绳索上从另一只的背上翻过去。如果一只狒狒想越过峡谷,它必须看当前是否有别的狒狒正在逆向通行。利用信号量编写一个避免死锁的程序来解决该问题。
不考虑连续东行的狒狒会使得西行的狒狒无限制地等待的情况。
【例题】
假设一个录像厅有1、2、3三种不同的录像片可由观众选择放映,录像厅的放映规则为:
1)任一时刻最多只能放映一种录像片,正在放映的录像片是自动循环放映的,最后一个观众主动离开时结束当前录像片的放映;
2)选择当前正在放映的录像片的观众可立即进入,允许同时有多位选择同一种录像片的观众同时观看,同时观看的观众数量不受限制;
3)等待观看其他录像片的观众按到达顺序排队,当一种新的录像片开始放映时,所有等待观看该录像片的观众可依次序进入录像厅同时观看。用一个进程代表一个观众,要求:用信号量方法PV操作实现,并给出信号量定义和初始值。
哲学家问题关键点是限制并行,主要是三种思路:
1. 限制申请资源的顺序 —— 破坏死锁循环等待条件(解法一不通用,不建议使用)
如:规定单号哲学家先取左筷子,双号先取右筷子
2. 信号量限制并发进程数(解法二通用,但并发度不高,不建议使用)
如:规定同一时间只能有一个哲学家就餐(禁止并行)
3. 让进程一口气取得所有资源,再开始运行(解放三很通用,且 并发度高,建议使用)
如:哲学家只有能够取得两个筷子的时候才会就餐
P(Lock); if(检查资源是否足够);V(Lock);
模板:用int型变量表示资源(并发度高)
【2019年统考】
(8分)有n (n≥3)位哲学家围坐在一张圆桌边,每位哲学家交替地就餐和思考。在圆桌中心有m (m≥1)个碗,每两位哲学家之间有一根筷子。每位哲学家必须取到一个碗和两侧的筷子后,才能就餐,进餐完毕,将碗和筷子放回原位,并继续思考。为使尽可能多的哲学家同时就餐,且防止出现死锁现象,请使用信号量的P、V操作 [wait()、signal()操作] 描述上述过程中的互斥与同步,并说明所用信号量及初值的含义。
【解析】
1、定义资源信号量、互斥信号量。
筷子和碗使用 int 型变量定义,便于加加减减。每支筷子属于不同类的资源。
PV操作只能对 semaphore型信号量 进行操作
- int wan = m;
- int a[n]={1,1,1...1}; //筷子,a[i]=1表示有右筷子,a[i-1]=1表示有左筷子
- semaphore mutex = 1; //互斥信号量
2、只要你出手就一定可以运行,所以可以保证并发度最高。
- philosopher(){
- while(1){
- P(mutex); //保证拿碗拿筷子的人只有一个
- if(wan<=0){ //没碗
- V(mutex);
- continue;
- }
- if( !(a[i]==1 && a[(i+1)%n]==1) ){ //少根筷子
- V(mutex);
- continue;
- }
- wan--;
- a[i]=0;a[(i+1)%n]=0; //拿筷子拿碗
- V(mutex);
- 进餐;
- }
- }
【例题】
俗话说,“干饭人,干饭魂,干饭人吃饭得用盆"。一荤、一素、一汤、一米饭,是每个干饭人的标配。饭点到了,很多干饭人奔向食堂。每个干饭人进入食堂后,需要做这些事:拿一个盆打荤菜,再拿一个盆打素菜,再拿一个盆打汤,再拿一个盆打饭,然后找一个座位坐下干饭,干完饭把盆还给食堂,然后跑路。现在,食堂里共有N个盆,M个座位。请使用P、V操作描述上述过程的互斥与同步,并说明所用信号量及初值的含义。
【解析】
显然,上面这种解法会导致死锁。假设同时来了好多个干饭人,每个人都拿三个盆,盆很快就会被拿光。那所有人都无法得到第四个盆,就会发生死锁。
下面我们模仿哲学家进餐问题的第二种解决思路。在哲学家问题中,共有5个哲学家,如果我们限制“最多允许4个哲学家同时进餐",那么至少会有一个哲学家可以同时获得左右两只筷子,并顺利进餐,从而预防了死锁。
同样的思路可以迁移到干饭人问题中。每个干饭人需要同时持有4个盆才能干饭,那么最糟糕的情况是每个干饭人都持有3个盆,同时在等待第四个盆。此时,但凡再多一个盆,就至少能有一个干饭人可以顺利干饭,就不会死锁。因此我们可以限制同时抢盆的人数为x,那么只要满足3x+1≤N,则一定不会发生死锁,可得x≤(N-1)/3。参考代码如下:
上面这种做法,限制了人数上限,且先拿盆,再占座,一定不会发生死锁。当然,如果先占座、后拿盆,也不会死锁。事实上,如果座位的数量满足seat ≤ (N-1)/3,那么甚至可以不设置专门的信号量x,完全可以先占座,后拿盆,也一定不会死锁。因为座位的数量就可以限制同时抢盆的人数。
下面我们再模仿哲学家问题的第三种解决思路一—仅当一个哲学家左右两边的筷子都可用时才允许哲学家拿筷子。其实就是破坏了请求和保持条件,采用"静态分配"的思想,让进程一口气获得所有资源,再开始运行。代码如下:
这个题目想告诉大家的是,哲学家进餐问题的解决思路中,后两种方法更为通用,可以作为考试时主要的策略。大家再思考一下,限制人数上限、一口气拿所有资源,哪种方案的并发度更高一些呢?显然是后者对吧。"限制人数上限""的方案中,最糟糕的情况是,只有一个人获得了4个盆,其余进程都只有3个盆,也就是说只有1个进程可以顺利运行下去,因此并发度低。
也可以使用int型变量解题。
- int pot=N;
- int seat=M;
- semaphore mutex=1;
-
- Eatman(){
- 进食堂;
- start:
- P(mutex);
- if(pot>=4) pot-=4;
- else{
- V(mutex);
- goto start;
- }
- }
【2009年计算机联考真题】
三个进程P1、P2、P3互斥使用一个包含N(N>0)个单元的缓冲区。P1每次用produce()生成一个正整数并用put)送入缓冲区某一空单元中;P2每次用getodd()从该缓冲区中取出一个奇数并用countodd()统计奇数个数;P3每次用geteven)从该缓冲区中取出一个偶数并用counteven()统计偶数个数。请用信号量机制实现这三个进程的同步与互斥活动,并说明所定义信号量的含义(要求用伪代码描述)。
【2011年计算机联考真题】
某银行提供1个服务窗口和10个供顾客等待的座位。顾客到达银行时,若有空座位,则到取号机上领取一个号,等待叫号。取号机每次仅允许一位顾客使用。当营业员空闲时,通过叫号选取一位顾客,并为其服务。顾客和营业员的活动过程描述如下。请添加必要的信号量和P、V(或wait()、signal())操作,实现上述过程中的互斥与同步。要求写出完整的过程,说明信号量的含义并赋初值。
【解析】
互斥资源:取号机(一次只允许一位顾客领号),因此设一个互斥信号量mutex对取号机进行管理;
同步问题:
顾客需要获得空座位等待叫号,当营业员空闲时,将选取一位顾客并为其服务。如果有空座位,新来的顾客可以到取号机上取号然后到座位上等待,如果无空座位,顾客不能取号。如果有顾客,营业员就得工作,如果无顾客,营业员可以休息,故设置两个信号量empty和full来实现这一同步关系。
另外,顾客获得空座位后,需要等待叫号和被服务。这样,顾客与营业员就服务何时开始又构成了一个同步关系,定义信号量service来完成这一同步过程。
- semaphore mutex = 1; //互斥使用取号机的信号量
- semaphore empty = 10; //空座位的数量信号量
- semaphore full = 0; //已占座位的数量信号量
- semaphore service = 0; //等待叫号信号量
- process 顾客i
- {
- P(empty);
- P(mutex);
- 从取号机获得一个号;
- V(mutex);
- V(full);
- P(service); //等待叫号
- }
- process 营业员
- {
- while (true) {
- P(full);
- V(empty);
- V(service); //叫号
- 为顾客服务;
- }
- }
【2013年计算机联考真题】
某博物馆最多可容纳500人同时参观,有一个出入口,该出入口一次仅允许一个人通过。参观者的活动描述如下,请添加必要的信号量和P、V(或wait()、signal())操作,以实现上述过程中的互斥与同步。要求写出完整的过程,说明信号量的含义并赋初值。
【2015年计算机联考真题】
有A、B两人通过信箱进行辩论,每个人都从自己的信箱中取得对方的问题。将答案和向对方提出的新问题组成一个邮件放入对方的邮箱中。假设A的信箱最多放M个邮件,B的信箱最多放N个邮件。初始时A的信箱中有x个邮件(0
【2017年计算机联考真题】
某进程中有3个并发执行的线程thread1、thread2和thread3,其伪代码如下所示。请添加必要的信号量和P、V(或wait()、signal())操作,要求确保线程互斥访问临界资源,并且最大限度地并发执行。
【解析】
若单独对 y和z 使用互斥信号量访问,则会扣1分。
因为未实现最大程度的并行。注意 线程 1,2 对y 仅进行读操作,而线程3 还进行了写操作。
y1本质上是T1和T3对于y的使用权;y2本质上是T2和T3对于y的使用权;
【2020年计算机联考真题】
现有5个操作A、B、C、D和E,操作C必须在A和B完成后执行,操作E必须在C和D完成后执行,请使用信号量的wait()、signal()操作(P、V操作光描述上述操作之间的同步关系,并说明所用信号量及其初值。
【2021年计算机联考真题】
下表给出了整型信号量S的wait ()和signal ()操作的功能描述,以及采用开关中断指令实现信号量操作互斥的两种方法。
请回答下列问题。
1)为什么在 wait ()和 signal ()操作中对信号量s的访问必须互斥执行?
2)分别说明方法1和方法2是否正确。若不正确,请说明理由。
3)用户程序能否使用开/关中断指令实现临界区互斥?为什么?