赞
踩
目录
描述:
基本流程:
注意1:先申请资源信号量,再申请互斥信号量,顺序不能颠倒,否则死锁
注意2:同一进程中的多个signal语句顺序颠倒对执行无影响,但先释放互斥再资源时性能更好
注意3:同一信号量的PV操作可以出现在不同进程中,但必须配对
注意4:在一个进程中,wait操作不一定就先于signal
示例1
一个生产者和两个消费者被连接到大小为N的缓冲区上
分析:
盘子是一互斥资源,故设置互斥信号量mutex
爸爸、儿子因为桔子的放入与取出而同步,设置产品资源信号量orange;
爸爸、女儿因为苹果的放入与取出而同步,设置产品资源信号量apple;
爸爸、儿子、女儿因为共享盘子,设置空间资源信号量empty。
程序:
- semaphore mutex=1;
- semaphore orange=0,apple=0,empty=N;
-
- void father(){
- while(true){
- P(empty);
- P(mutex);
- //进入临界区,放置水果为result
- V(mutex)
- if (result == apple) V(apple);
- else V(orange);
-
- void son(){
- whlie(true){
- P(orange);
- p(mutex);
- //进入临界区,拿走橘子
- V(mutex);
- v(empty);
- }
- }
-
- void daughter(){
- while(true){
- P(apple);
- P(mutex);
- //进入临界区,拿走苹果
- V(mutex);
- V(empty);
- }
- }
示例2
两个生产者和两个消费者被连接到大小为1的缓冲区上
分析:
盘子是一互斥访问的空间资源,且缓冲大小为1,可只设置一个盘子资源信号量plate = 1
爸爸、女儿因为苹果的放入与取出而同步,设置产品资源信号量apple = 0;
妈妈、儿子因为桔子的放入与取出而同步,设置产品资源信号量orange = 0;
代码:
- semaphore plate=1, apple=0, orange=0;
-
- void father(){
- while(true){
- P(plate);
- //放苹果
- V(apple)
- }
- }
- void mother(){
- while(true){
- P(plate);
- //放橘子
- V(orange);
- }
- }
- void son(){
- while(true){
- P(orange);
- //拿橘子
- V(plate);
- }
- }
- void daughter(){
- while(true){
- P(apple);
- //拿苹果
- V(plate);
- }
- }
例3
两个生产者和一个消费者被连接到大小为2的缓冲区上
分析:
盘子中是否可以放入苹果,设置空间资源信号量empty_apple;
盘子中是否可以取出苹果,设置产品资源信号量apple;
盘子中是否可以放入桔子,设置空间资源信号量empty_orange;
盘子中是否可以取出桔子,设置产品资源信号量orange
题中只说到“放入者和取出者不允许同时使用盘子”,那两个放入者可以同时使用盘子。所以不需要对盘子额外设置生产者的互斥信号量
程序:
- semaphore empty_apple=1, empty_orange=1;
- semaphore apple=0, orange=0;
-
- void father(){
- while(true){
- P(empty_apple);
- //放苹果
- V(apple);
- }
- }
- void mother(){
- while(true){
- P(empty_orange);
- //放橘子
- V(orange);
- }
- }
- void dauther(){
- while(true){
- P(apple);
- P(orange);
- //同时拿走苹果和橘子
- V(orange);
- V(apple);
- }
- }
例4
一个生产者和两个消费者,一幅画要分别给两人看
分析:
题中说的是“均欣赏一遍后”,也没强调是“依次”欣赏,再结合实际可认为消费者之间不需要互斥(可以理解为,消费者只读,不互斥)
爸爸是否欣赏过,设置空间资源信号量empty_dad;
爸爸是否可以欣赏,设置产品资源信号量full_dad;
妈妈是否欣赏过,设置空间资源信号量empty_mom;
妈妈是否可以欣赏,设置产品资源信号量full_mom。
(其实对于爸爸妈妈是否可以访问也可以就只设置一个full=2的信号量就行)
程序:
- semaphore empty_dad = 1, empty_mom = 1;
- semaphore full_dad = 0, full_mom = 0;
-
- void daughter(){
- while(true){
- P(empty_dad);
- P(empty_mom)
- //作画
- V(full_dad);
- V(full_mom);
- }
- }
- void mother(){
- while(true){
- P(full_mom);
- //看画
- V(empty_mom);
- }
- }
- void father(){
- while(true){
- P(full_dad);
- //看画
- V(empty_dad);
- }
- }
如何判断一个问题是生产者/消费者问题,还是读者/写者问题?
例1. 读者优先
描述:
信号量设置:
wsem:互斥信号量,用于Writers间互斥,Writers和Readers互斥
readcount:统计同时读数据的Readers个数
x:对变量readcount互斥算术操作
- semaphore wsem=1, x=1;
- int readcount=0;
-
- void reader(){
- while(true){
- P(x);
- readcount++;
- if (readcount == 1) P(wsem);
- V(x);
- //读数据
- P(x);
- readcount--;
- if (readcount == 0) V(wsem);
- V(x)
- }
- }
-
- void writer(){
- while(true){
- P(wsem);
- //写数据
- V(wsem)
- }
- }
例2. 公平读写
描述:
写过程中,若其它读者、写者到来,则按到达顺序处理
读过程中,若其他读者到来,直接进入临界区读数据
信号量设置:
wsem:互斥信号量,用于Writers间互斥,Reader互斥Writers
readcount:统计同时读数据的Readers个数
x:对变量readcount互斥算术操作
wrsem:互斥信号量,确定Writer 、Reader请求顺序
程序:
- semaphore x=l, wrsem=1, wsem=l;
- int readcount=0;
-
- void reader() {
- while (true) {
- P(wrsem);
- P(x);
- readercount++;
- if (readercount == 1) P(wsem);
- V(x);
- V(wrsem);
- //读数据;
- P(x);
- readercount--;
- if (readercount == 0) V(wsem);
- V(x);
- }
- }
- void writer(){
- while(true){
- P(wrsem);
- P(wsem);
- //写数据;
- V(wsem);
- V(wrsem);
- }
- }
例3 写者优先
描述:
信号量设置:
rsem:互斥信号量,当至少有一个写者申请写数据时互斥新的读者进入读数据,第一个写者受rsem影响,一旦有第一个写者,后续写者不受rsem其影响。但是读者需要在rsem上排队。
writecount:用于控制rsem信号量
y:对变量writecount互斥算术操作
程序:
- int readcount = 0, writecount = 0;
- semaphore x=l, y= 1, wsem=1, rsem=l;
-
- void reader(){
- while(true){
- P(rsem);
- P(x);
- readcount++;
- if (readcount==1) P(wsem);
- V(x);
- V(rsem);
- //读数据
- P(x);
- readcount--;
- if (readcount==0) V(wsem);
- V(x);
- }
- }
- void writer(){
- while(true){
- P(y);
- writecount++;
- if (writecout==1) P(rsem);
- V(y);
- P(wsem);
- //写数据
- V(wsem);
- P(y);
- writecount--;
- if (writecount==0) V(rsem);
- V(y);
- }
- }
缺陷:WRRRR队列,W会等待长R队列
改进 : 增加z信号量,只对读者起作用
在rsem上不允许建造读进程的长队列,否则写进程将不能跳过这个队列.
允许一个读进程在rsem上排队,其他读进程在信号量z上排队
- int readcount = 0, writecount = 0;
- semaphore x=l, y= 1, wsem=1, rsem=l,z=1;
-
- void reader(){
- while(true){
- P(z)
- P(rsem);
- P(x);
- readcount++;
- if (readcount==1) P(wsem);
- V(x);
- V(rsem);
- V(z)
- //读数据
- P(x);
- readcount--;
- if (readcount==0) V(wsem);
- V(x);
- }
- }
- void writer(){
- while(true){
- P(y);
- writecount++;
- if (writecout==1) P(rsem);
- V(y);
- P(wsem);
- //写数据
- V(wsem);
- P(y);
- writecount--;
- if (writecount==0) V(rsem);
- V(y);
- }
- }
例4 过桥问题1
有一座东西方向的独木桥,同一方向的行人可连续过桥。当某一方向有行人过桥时,另一方向行人必须等待。桥上没有行人过桥时,任何一端的行人均可上桥。请用P、V操作来实现东西两端人过桥问题。
分析:
读者优先问题的变化,思想类似读者优先
两组读者,同一组之间可以同时读,不同组之间互斥,即只要有一组读者上桥,同组读者优先于另一组读者
桥-共享数据
murex:互斥信号量,用于两组读者互斥写者
countR:统计读者数目(同时在桥上的行人数目)
xR:对变量countR互斥算术操作
程序:
- int countA=0, countB=0;
- semaphore mutex=1, xA=1, xB=1;
-
- void east_west(){
- while(1){
- P(xA)
- countA++;
- if (countA==1) P(mutex);
- V(xA);
- //过桥
- P(xA);
- countA--;
- if (countA==0) V(mutex);
- V(xA);
- }
- }
- void west_east(){
- while(1){
- P(xB);
- countB++;
- if (countB==1) P(mutex);
- V(xB);
- //
- P(xB);
- countB--;
- if (countB==0) V(mutex);
- V(xB)
- }
- }
例5 过桥问题2
有一座东西方向的独木桥,同一方向的行人可连续过桥。当某一方向有行人过桥时,另一方向行人必须等待。桥上没有行人过桥时,任何一端的行人均可上桥。出于安全考虑,独木桥的最大承重为4人,即同时位于桥上的行人数目不能超过4。请用P、V操作来实现东西两端人过桥问题
分析:
类似上题,需引入信号量count=4来统计桥上人数,在进入临界区前后对count进行P、V
- int countA=0, countB=0;
- semaphore mutex=1, xA=1, xB=1, count=4;
-
- void east_west(){
- while(1){
- P(xA)
- countA++;
- if (countA==1) P(mutex);
- V(xA);
- P(count)
- //过桥
- V(count)
- P(xA);
- countA--;
- if (countA==0) V(mutex);
- V(xA);
- }
- }
- void west_east(){
- while(1){
- P(xB);
- countB++;
- if (countB==1) P(mutex);
- V(xB);
- P(count)
- //过桥
- V(count)
- P(xB);
- countB--;
- if (countB==0) V(mutex);
- V(xB)
- }
- }
描述:
分析:
-
- semaphore barber=1 //理发师是否就绪
- semaphore ready=0; //顾客是否就绪
- semaphore wait=5; //空椅子个数
- int num_customer=0; //店里顾客总人数,等于6时新顾客离开
- semaphore mutex_num=1 //对num_customer互斥访问
- semaphore finish=0; //理发师是否完成理发
- void customer(){
- while(true){
- p(mutex_num);
- if num_customer<6{
- num_customer++;
- V(mutex_num);
- P(wait); //找空椅子坐下
- P(barber); //找理发椅坐下
- V(wait); //释放空椅子
- V(ready); //告知理发师该顾客准备好了
- P(finish); //等待完成理发
- V(barber); //释放理发椅
- p(mutex_num);
- num_customer--;
- V(P_mutex);
- }
- else V(num_mutex) 离开;
- }
- }
-
- void Baber(){
- while(1){
- P(ready);
- //理发
- V(finish);
- }
- }
补充:理发师睡觉类似问题
银行提供一个服务窗口和10个供顾客等待的座位。顾客到达银行时,若有空座位,则到取号机上领取一个号,等待叫号。取号机每次仅允许一位顾客使用。当营业员空闲时,通过叫号选取一位顾客,并为其服务
- semaphore mutex = 1; //互斥使用取号机的信号量
- semaphore empty = 10; //空座位的数量信号量
- semaphore full = 0; //已占座位的数量信号量
- semaphore service = 0; //等待叫号信号量
-
- void customer_i(){
- P(empty);
- P(mutex);
- //取号
- V(mutex);
- V(full);
- P(service);
- V(empty);
- //获取服务
- }
- void server(){
- while(1){
- P(full)
- V(serveice)
- //服务
- }
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。