PV操作经典问题通解
PV操作经典问题包括:读者写者问题,生产者消费者问题,哲学家就餐问题,理发师问题。
下面先给出解题通用步骤,再对每一类问题做例题分析,并给出每类问题的特解。
一 PV操作思考通用步骤:
1.有几类进程?每类进程对应一个函数。
如
生产者1进程对应producer1()
消费者1进程对应consumer1()
消费者2进程对应consumer2()
2.在函数内部用中文描述动作,并在草纸上行间留白供后续使用,并根据这些动作是否重复进行,决定是否加while(1)
如
producer{while(1){生产一件商品;把商品放到货架;}}
3.在每个动作之前,思考是否需要P什么?如果需要P操作,写出P操作,并写出对应的V操作(V操作可能在另一进程内)
如
producer{while(1){//不需要P生产一件商品;//由于需要消耗货架容量,所以需要P(货架空闲区)//货架属于临界资源需要互斥访问,所以P(货架互斥信号量)把商品放到货架;//P的对应V操作:释放临界资源,所以V(货架互斥信号量)//由于货架被放上货物,货物量增加,所以V(货架货物量)
4.写完PV操作后,再完整地定义信号量
如
semaphore mutex=1;//临界资源semaphore empty=5//空闲区数量semaphore full=0//货物数量int count=0;//整形信号量,用于统计人数等semaphore CSignal;//在count++ count————时,套上P()V(),实现互斥更改count值
5.完成上述步骤之后进行检查,检查多个P操作连续出现时是否可能出现死锁。一对PV前后出现,不会死锁;连续多个P导致死锁(请求和保持),可尝试调换前后P的顺序。
二生产者消费者问题
例一用于实操一遍通解过程的1,2,3,4,5步,例二用于说明第5步会遇到的问题。
例一:某工厂有两个生产车间和一个装配车间,两个生产车间分别生产 A、B 两种零件,装配车间的任务是把 A、B 两种零件组装成产品。两个生产车间每生产一个零件后,都要分别把它们送到装配车间的货架 F1、F2上。F1 存放零件 A,F2 存放零件 B,F1 和 F2 的容量均可存放 10 个零件。装配工人每次从货架上取一个零件 A 和 一个零件 B 后组装成产品。请用 P、V 操作进行正确管理。
思考步骤,解体流程:
1.有几类进程?每类进程对应一个函数。
如
生产者A进程对应producerA()
生产者B进程对应producerB()
消费者进程对应consumer()
2.在函数内部用中文描述动作,并在草纸上行间留白供后续使用,并根据这些动作是否重复进行,决定是否加while(1)
如
producerA{while(1){生产一件零件A;把零件A放到货架F1;}}producerB{while(1){生产一件零件B;把零件B放到货架F2;}}consumer{while(1){从货架F1取一件零件A;从货架F2取一件零件B;把零件A和B组装;}}
3.在每个动作之前,思考是否需要P什么?如果需要P操作,写出P操作,并写出对应的V操作(V操作可能在另一进程内)
如
producerA{while(1){生产一件零件A;P(emptyF1)//由于需要消耗货架容量,所以需要P(货架空闲区)P(mutexF1)//货架属于临界资源需要互斥访问,所以P(货架互斥信号量)把零件A放到货架F1;V(mutexF1);//P的对应V操作:释放临界资源,所以V(货架互斥信号量)V(fullF1)//由于货架被放上货物,货物量增加,所以V(货架货物量)}}producerB{while(1){生产一件零件B;P(emptyF2)//由于需要消耗货架容量,所以需要P(货架空闲区)P(mutexF2)//货架属于临界资源需要互斥访问,所以P(货架互斥信号量)把零件B放到货架F2;V(mutexF2);//P的对应V操作:释放临界资源,所以V(货架互斥信号量)V(fullF2)//由于货架被放上货物,货物量增加,所以V(货架货物量)}}consumer{while(1){P(fullF1)//由于需要消耗货物A,所以需要P(货架货物量)P(mutexF1)//货架属于临界资源需要互斥访问,所以P(货架互斥信号量)从货架F1取一件零件A;V(mutexF1);//P的对应V操作:释放临界资源,所以V(货架互斥信号量)V(emptyF1)//取完货物,货架F1空闲区增加,所以V(货架空闲区)P(fullF2)//由于需要消耗货物B,所以需要P(货架货物量)P(mutexF2)//货架属于临界资源需要互斥访问,所以P(货架互斥信号量)从货架F2取一件零件B;V(mutexF2);//P的对应V操作:释放临界资源,所以V(货架互斥信号量)V(emptyF2)//取完货物,货架F2空闲区增加,所以V(货架空闲区)把零件A和B组装;}}
4.写完PV操作后,再完整地定义信号量
如
semaphore mutexF1=1;//临界资源semaphore mutexF2=1;semaphore emptyF1=10;//空闲区数量semaphore emptyF2=10;semaphore full1F=0;//货物数量semaphore full2F=0;
5.完成上述步骤之后进行检查,检查多个P操作连续出现时是否可能出现死锁。一对PV前后出现,不会死锁;连续多个P导致死锁(请求和保持),可尝试调换前后P的顺序。
未发现死锁现象,完整答案:
semaphore mutexF1=1;//临界资源semaphore mutexF2=1;semaphore emptyF1=10;//空闲区数量semaphore emptyF2=10;semaphore full1F=0;//货物数量semaphore full2F=0;producerA{while(1){生产一件零件A;P(emptyF1)//由于需要消耗货架容量,所以需要P(货架空闲区)P(mutexF1)//货架属于临界资源需要互斥访问,所以P(货架互斥信号量)把零件A放到货架F1;V(mutexF1);//P的对应V操作:释放临界资源,所以V(货架互斥信号量)V(fullF1)//由于货架被放上货物,货物量增加,所以V(货架货物量)}}producerB{while(1){生产一件零件B;P(emptyF2)//由于需要消耗货架容量,所以需要P(货架空闲区)P(mutexF2)//货架属于临界资源需要互斥访问,所以P(货架互斥信号量)把零件B放到货架F2;V(mutexF2);//P的对应V操作:释放临界资源,所以V(货架互斥信号量)V(fullF2)//由于货架被放上货物,货物量增加,所以V(货架货物量)}}consumer{while(1){P(fullF1)//由于需要消耗货物A,所以需要P(货架货物量)P(mutexF1)//货架属于临界资源需要互斥访问,所以P(货架互斥信号量)从货架F1取一件零件A;V(mutexF1);//P的对应V操作:释放临界资源,所以V(货架互斥信号量)V(emptyF1)//取完货物,货架F1空闲区增加,所以V(货架空闲区)P(fullF2)//由于需要消耗货物B,所以需要P(货架货物量)P(mutexF2)//货架属于临界资源需要互斥访问,所以P(货架互斥信号量)从货架F2取一件零件B;V(mutexF2);//P的对应V操作:释放临界资源,所以V(货架互斥信号量)V(emptyF2)//取完货物,货架F2空闲区增加,所以V(货架空闲区)把零件A和B组装;}}
例二:某寺庙有小和尚、老和尚若干,有一水缸,由小和尚提水入缸供老和尚引用。水缸可容 10 桶水,水桶自同一井中。水井径窄,每次只能容一个桶取水。水桶总数为 3 个。每次入缸取水仅为 1 桶水,且不可同时进行。试给出有关从缸取水、入水的算法描述。
先给出正确解答,再说明第5步可能出现的问题。
semaphore well = 1; //用于互斥地访问水井;
semaphore vat = 1; //用于互斥的访问水缸;
semaphore empty = 10; //用于表示水缸中剩余空间;
semaphore full = 0; //表示水缸中水的桶数;
semaphore pail = 3; //表示有多少个水桶可以用,初始值为3;// 老和尚
while(1){P(full);P(pail); P(vat);从水缸中打一桶水;V(vat);V(empty);喝水;V(pail);
}// 小和尚
while(1){P(empty);P(pail);P(well);从井中打一桶水;V(well);P(vat);将水倒入水缸中;V(vat);V(full);V(pail);
}
我们在写P操作时,遇到的多个P操作,应该先写哪个P呢?我给出策略1可以把互斥访问临界资源的P(mutex)放在最后,而前面的多个P可能不确定,假如老和尚写成
P(pail);//取桶P(full);//确定有水 P(vat);//互斥缸从水缸中打一桶水;
而此时缸中无水,且有3个和尚共取了3个桶,那么小和尚无法取桶去取水,老和尚就永远喝不到水,产生死锁。
这时我们就应该调换P操作顺序为
P(full);P(pail); P(vat);从水缸中打一桶水;
那么我们就会产生疑问,有没有一种思考方式来直接避免多个P出现死锁呢?下面我给出一种策略2
如果我们要做两件事,且先做A,再做B,那么我们就应该先确保做B所需资源存在,再确定做A所需资源存在。
比如老和尚要喝水,两件事:先取桶,再从缸里取水,那么我们就应该先确定缸里水存在,再确定桶存在。用PV描述:
P(full);确定缸里水存在P(pail);确定桶存在
再比如小和尚要取水,两件事:先从用桶从井里取水,再把水倒入缸中空闲区,那么我们就应该先确定缸中空闲区存在,再确定桶存在。用PV描述:
P(empty);P(pail);
三读者写者问题
对读者优先,读写公平,写者优先三种策略,我们按照通解写出答案,再对特殊部分进行解读。
三.1读者优先
按照通解得到:
semaphore RCsignal=1;//读者数修改互斥
semaphore mutex=1;//临界资源互斥
int count=0;//读者数读者部分:
reader(){while(1){P(mutex);读;V(mutex);}
}写者部分:
writer(){while(1){P(mutex);写;V(mutex);}
}
使用了整形信号量readcount,目的是在第一个读者进入临界资源时,锁住临界资源,使后续读者可以继续访问而后续写者无法访问;在最后一个读者撤出临界资源时,解锁临界资源,使后续读者或写者都可访问。
semaphore RCsignal=1;//读者数修改互斥
semaphore mutex=1;//临界资源互斥
int count=0;//读者数读者部分:
reader(){while(1){P(RCsignal);if(count==0)P(mutex);V(RCsignal);读;P(RCsignal);count--;if(count==0)V(mutex);V(RCsignal);}
}写者部分:
writer(){while(1){P(mutex);写;V(mutex);}
}
三.2读写公平
读写公平分为两种,一种是部分自行抢占部分先来先服务,一种是先来先服务。
两者的PV操作区别是写者中P(rw)的位置不同。
书中,博客中所给的基本都是第一种读写公平,个人认为第二种是更公平的写法。
部分自行抢占,部分先来先服务:写者A在访问临界资源时,又先后来了B,C,那么B,C有同等概率先访问临界资源;读者A在访问临界资源时,又
先后来了B,C,那么B将优先于C先访问临界资源。
部分自行抢占部分先来先服务的具体机制
部分自行抢占部分先来先服务{目前临界资源正被某读者A访问{若此时先后来到一个读者B,一个写者C{B与A同时读;}若此时先后来到一个写者B,一个读者C{A出后,B写;}目前临界资源正被某写者A访问{若此时先后来到一个读者B,一个写者C{A出后,BC有同等概率抢占临界资源;}若此时先后来到一个写者B,一个读者C{A出后,BC有同等概率抢占临界资源;}}
如何实现这个机制呢?
我们引入一个信号量rw,当A在读时,来B,B即获得下一位进入临界区的资格。所以B(无论时读写)应首先P(rw),获得资格,此时若再来C,则C被P(rw)阻塞,即C无法获得资格。
若B为写,已经获得资格,那么B什么时候再释放这个资格呢?答案是当B写完,B写完后,后续来者自行抢占。
若B为读,已经获得资格,那么B什么时候再释放这个资格呢?答案是当B在读之前,因为读时B已经像A那样允许下一位获得资格。
semaphore mutex=1;
semaphore RCsignal=1;
semaphore rw=1;
int count=0;读者部分:
reader(){while(1){P(rw);P(RCsignal);if(count==0)P(mutex);count++;V(RCsignal);V(rw);读;P(RCsignal);count--;if(count==0)V(mutex);V(RCsignal);}
}写者部分:
writer(){while(1){P(rw);P(mutex);写;V(mutex);V(rw);}
}
先来先服务:简单来说A在访问临界资源时,又先后来了B,C,那么B将优先于C先访问临界资源。
先来先服务的具体机制:
先来先服务{目前临界资源正被某读者A访问{若此时先后来到一个读者B,一个写者C{B与A同时读;}若此时先后来到一个写者B,一个读者C{A出后,B写;}目前临界资源正被某写者A访问{若此时先后来到一个读者B,一个写者C{A出后,B读;}若此时先后来到一个写者B,一个读者C{A出后,B写;}}
如何实现这个机制呢?
我们引入一个信号量rw,当A在读或写时,来B,B即获得下一位进入临界区的资格。所以B(无论时读写)应首先P(rw),获得资格,此时若再来C,则C被P(rw)阻塞,即C无法获得资格。
B已经获得资格,那么B什么时候再释放这个资格呢?答案是当B在读写之前,因为读写时B已经像A那样允许下一位获得资格。
semaphore mutex=1;
semaphore RCsignal=1;
semaphore rw=1;
int count=0;读者部分:
reader(){while(1){P(rw);P(RCsignal);if(count==0)P(mutex);count++;V(RCsignal);V(rw);读;P(RCsignal);count--;if(count==0)V(mutex);V(RCsignal);}
}写者部分:
writer(){while(1){P(rw);P(mutex);V(rw);写;V(mutex);}
}
三.3写者优先
写者优先的规则:
1.读者与写者,写者与写者不能同时访问缓冲区;
2.无写进程时,各读者可同时访问缓冲区;
3.读者和写者都等待时,写者优先访问缓冲区;
“读者和写者都等待时,写者优先访问缓冲区”解读
读者写者都等待的情况,即有写者正在访问临界资源,而不可能是有读者正在访问临界资源,这是因为有读者在访问临界资源时,后到的写者 只能等待访问临界资源的读者撤出后 才能访问临界资源(读者写者问题的基本原则),而后到的读者可以与前面的读者共同访问临界资源。
写优先代码解读
在读者写者都等待的情况,即有写者正在访问临界资源时,write=0(代码中写了,当访问临界资源的写者撤出时,Wcount=0,才会V(write),使write=0),假如此时按时间顺序又来了读者A,写者B。此时在write=0的情况下,按时间顺序读者A先执行P(write),即读者A被阻塞;然后按时间顺序写者B执行,由于此时Wcount=1,即P(write)语句不会执行,即不会在此阻塞,继续执行直到P(mutex)被阻塞。目前读者A与写者B都处于阻塞状态。但一旦正在访问临界资源的写者退出并执行V(mutex)后,使得mutex=1,并且写者B得知mutex=1,并执行P(mutex),进而进行“写”。A退出时,Wcount=1,因此不会V(write),因此读者B将继续被阻塞。
此时即实现了,在读者写者都等待时,即有写者正在访问临界资源的情况下,按时间顺序又来了读者A,一个写者B,而执行结果就是,读者A被阻塞,写者B也被阻塞。但一旦正在访问临界资源的写者退出并执行V(mutex)后,写者B进行“写”,即写者B先于读者A,实现了插队。即读者和写者都等待时,写者优先访问缓冲区。
semaphore write=1;//进程优先互斥
semaphore mutex=1;//临界资源互斥
semaphore RCsignal=1;//读者数Rcount修改互斥
semaphore WCsignal=1;//写者数Wcount修改互斥
int Rcount=0;//读者数
int Wcount=0;//写者数读者部分:
reader(){while(1){P(write);P(RCsignal);if(Rcount==0)P(mutex);Rcount++;V(RCsignal);V(write);读;P(RCsignal);Rcount--;if(Rcount==0)V(mutex);V(RCsignal);}
}写者部分:
writer(){while(1){P(WCsignal);if(WCsignal==0)P(write);Wcount++;V(WCsignal);P(mutex);写;V(mutex);P(WCsignal);Wcount--;if(Wcount==0)V(write);V(WCsignal);}
}
四哲学家进餐问题
哲学家进餐问题的特点是只有一类进程,且进程数量小于资源数量。
解决方法是当一个进程能够得到所有需要的资源时,再一次性取走这些资源。
通解:
process(){while(1){P(mutex);//用于互斥访问资源 if(资源A>=a&&资源B>=b){//如果所有资源都足够资源A--;//一次性获得全部资源资源B--;V(mutex);break;//已经获得资源,跳出循环,至做事} elseV(mutex); //资源不够,重复查询}做事;//比如哲学家吃饭P(mutex);//互斥访问资源资源A++;//一次性退还全部资源资源B++;V(mutex); }
五理发师问题
实在复杂,这里跳向一篇好文。
链接: https://blog.csdn.net/duanzhengbing/article/details/52141699
PV操作经典问题通解相关推荐
- PV操作经典例题——吃水果
例1:桌上有一个盘子,每次只能放一个水果,妈妈向盘中放苹果和橘子,儿子专等吃盘里的橘子,女儿专等吃盘里的苹果.只要盘子空,妈妈可向盘中放水果,仅当盘中有自己需要的水果时,儿子或女儿可从中取出,请给出他 ...
- 【操作系统】PV 操作经典例题---三个进程之间的同步
问题: 总共有 读入.执行.打印 三个进程,试用PV操作描述读入B1打印B2的同步过程. 问题解读: 这个问题就是说了这样一件事:一个输入B1,被操作之后,成为B2,将B2打印.怎样用PV操作来说这件 ...
- PV 操作经典例题---三个进程之间的同步
问题: 总共有 读入.执行.打印 三个进程,试用PV操作描述读入B1打印B2的同步过程. 问题解读: 这个问题就是说了这样一件事:一个输入B1,被操作之后,成为B2,将B2打印.怎样用PV操作来说这件 ...
- PV操作经典例题——哲学家进餐问题
哲学家进餐问题: 五个哲学家共用一张圆桌,分别坐在周围的五张椅子上,在桌子上有五只碗和五只筷子,他们的生活方式是交替地进行思考和进餐.平时,一个哲学家进行思考,饥饿时便试图取用其左右最靠近他的筷子,只 ...
- PV操作经典例题——司机与售票员的进程同步问题
例1: 司机的活动: 启动车辆, 正常行车, 到站停车. 售票员活动: 关车门, 售票, 开车门. 注意:当发车时间到,售票员关好车门后,司机才能启动车辆,售票员才开始售票. 当到站时,司机停稳车后, ...
- PV操作经典例题——银行业务办理问题
例:某银行提供1个服务窗口和10个供顾客等待的座位,顾客到达银行时,若有空座位,则到取号机上领取一个号,等待叫号.取号机每次仅允许一位顾客使用,当营业员空闲时,通过叫号选取一位顾客,并为其服务. 解析 ...
- java实现的PV操作经典例子:读者写者、贪睡的理发师、生产者消费者。
其中读者写者和贪睡的理发师使用的Semaphore类:生产者消费者使用的是管程. 读者写者 class Semaphore {int value;public Semaphore(int v){thi ...
- 几个java实现的PV操作经典例子:读者写者、贪睡的理发师、生产者消费者
其中读者写者和贪睡的理发师使用的Semaphore类:生产者消费者使用的是管程. 读者写者: class Semaphore {int value;public Semaphore(int v){th ...
- 操作系统 | PV操作七大经典问题 生产者消费者 读者写者 哲学家进餐 理发师理发睡觉 和尚打水 吸烟者 吃水果
一.生产者消费者问题 生产者消费者问题(英语:Producer-consumer problem),也称有限缓冲问题(英语:Bounded-buffer problem),是一个多线程同步问题的经典案 ...
- 【操作系统】经典PV操作题目
5个经典PV操作题(附答案) 三个进程之间的同步 pv操作的经典习题 PV操作题型整理 生产者和消费者 生产者消费者问题 当只有一个生产者和一个消费者的时候,且只有一个缓冲区 要考虑生产者和消费者两个 ...
最新文章
- 【ACM】杭电OJ 2018
- Python-PyCharm 报错解决:ImportError: cannot import name 'InteractiveConsole' from 'code'
- Cloud一分钟 | 马云发表致股东的公开信;5G算什么?中国已着手研究6G相关工作...
- 酷睿i7cpu适合的linux,CPU性能篇 - Core i7-4770K Linux之旅:有喜有忧_Linux新闻_Linux公社-Linux系统门户网站...
- LTE物理传输资源(2)-频带、信道带宽和频点号EARFCN
- dos.ORM配置和使用
- windows自动导出oracle数据库,Oracle数据库的自动导出备份脚本(windows环境)
- 编译OpenJDK8:NMAKE : fatal error U1077
- C++ string append方法的常用用法
- oracle系统卸载干净,完全卸载oracle|oracle卸载|彻底卸载oracle
- css inset属性
- 工具使用,PS隐藏技能—对称绘画
- 每天学一个 Linux 命令:dnf
- 军团要塞2正版服务器,Team Fortress 2
- layui js 自定义打印功能实现
- js循环绑定事件问题及解决方法
- 【均衡器】LS均衡器,DEF均衡器以及LMMSE均衡器的误码率性能对比仿真
- 教你轻松用Python画一只肥肥的柯基狗狗——turtle库绘制椭圆与弧线实践
- ABBYY FineReader PDF15下载安装教程
- 基于MATLAB的图像压缩感知