经典PV操作问题详解最全面的PV资料.docx

上传人:b****8 文档编号:9748064 上传时间:2023-02-06 格式:DOCX 页数:21 大小:31.53KB
下载 相关 举报
经典PV操作问题详解最全面的PV资料.docx_第1页
第1页 / 共21页
经典PV操作问题详解最全面的PV资料.docx_第2页
第2页 / 共21页
经典PV操作问题详解最全面的PV资料.docx_第3页
第3页 / 共21页
经典PV操作问题详解最全面的PV资料.docx_第4页
第4页 / 共21页
经典PV操作问题详解最全面的PV资料.docx_第5页
第5页 / 共21页
点击查看更多>>
下载资源
资源描述

经典PV操作问题详解最全面的PV资料.docx

《经典PV操作问题详解最全面的PV资料.docx》由会员分享,可在线阅读,更多相关《经典PV操作问题详解最全面的PV资料.docx(21页珍藏版)》请在冰豆网上搜索。

经典PV操作问题详解最全面的PV资料.docx

经典PV操作问题详解最全面的PV资料

经典P、V操作问题详解

lionxcat@

一、基本概念

1.信号量

structsemaphore

{

intvalue;//仅且必须附初值一次,初值非负

PCBtype*wait_queue;//在此信号量上阻塞的进程队列

}S;//信号量实例为S

2.P、V操作

P(S){

S:

=S-1;

if(S<0)

调用进程自己阻塞自己,等待在S的等待队列末尾;

}

V(S){

S:

=S+1;

if(S≤0)

从S等待队列头释放一进程就绪在就绪队列尾;

调用进程继续执行;

}

3.使用方法

(i).P、V操作成队出现,处理互斥时出现在同一进程中;处理同步时出现在不同进程中。

(ii).同步P先于互斥P调用,V的顺序无关。

4.另类P、V操作导致的问题(或信号量的栈实现方法或漏斗法)

[习题P174-23]

某系统如此定义P、V操作:

P(S):

S=S-1;若S<0,本进程进入S信号量等待队列的末尾;否则,继续执行。

V(S):

S=S+1;若S≤0,释放等待队列中末尾的进程,否则继续运行。

(1)上面定义的P、V操作是否合理?

有什么问题?

(2)现有四个进程P1、P2、P3、P4竞争使用某一个互斥资源(每个进程可能反复使用多次),试用上面定义的P、V操作正确解决P1、P2、P3、P4对该互斥资源的使用问题。

答:

(1)不合理:

先进后出;可能“无限等待”,即等待队列头的进程得不到释放。

(2)思路:

令每个信号量上的等待队列中始终只有一个进程。

解决方案如下:

(n个进程)

n个进程至多有n-1个等待。

设置n-1个信号量,每个进程阻塞在不同的信号量上,使每个等待队列至多有一个进程等待。

用循环模拟队列。

SemaphoreS[n-1];//S[i]的初值为i+1

Procedure_i()

{

intj;

DO_PRE_JOB();

for(j=n-2;j>=0;j--)

P(S[j]);

DO_JOB_IN_CRITICAL_SECTION();

for(j=0;j<=n-2;j++)

V(S[j]);

……

}

二、经典进程同步问题

总述:

进程同步问题主要分为以下几类:

一(生产者-消费者问题);二(读者写者问题);三(哲学家就餐问题);四(爱睡觉的理发师问题);五(音乐爱好者问题);六(船闸问题);七(红黑客问题)等。

其中前两类都是用于处理进程之间通信的问题:

生产者-消费者问题主要实现进程的消息机制,而读者-写者问题用于实现管道通信。

哲学家就餐问题是经典的互斥转同步防止死锁的多资源争夺。

理发师问题适合I/O或外部设备的管理,如打印调度。

红黑客问题是解决不同条件触发事件的思想方法。

I.生产者—消费者问题(初始缓冲区为空)

问题:

生产者生产产品放到缓冲区,消费者从缓冲区取产品消费。

①单缓冲区[书P119](适合单或多生产消费者):

同步:

生产者不能往满缓冲区放产品(S1

(1));消费者不能从空缓冲区取产品(S2(0))。

voidProducer()

{

while(true){

生产一个产品;

P(S1);申请一个空的缓冲区

放到缓冲区;

V(S2);返回一个满的缓冲区

}}

voidConsumer()

{

while(true){

P(S2);申请一个满的缓冲区

从缓冲区取一个产品;

V(S1);返回一个空的缓冲区

消费产品;

}}

②环行多缓冲区(或无穷缓冲区)单生产消费者[习题P173-13]:

同步:

生产者不能往满缓冲区放产品(S1(n));消费者不能从空缓冲区取产品(S2(0))。

n为缓冲区大小。

互斥:

设置指示下一个空缓冲区的位置变量(i(0))和指示下一个产品在缓冲区的位置变量(j(0)),由于只有一个生产者和消费者,i和j无须互斥访问。

此问题无互斥关系。

voidProducer()

{

while(true){

生产了一个产品;

P(S1);

把产品放入缓冲区;

i=(i+1)%n;//无穷缓冲区无须’%n’

V(S2);

}}

voidConsumer()

{

while(true){

P(S2);

取一个产品;

j=(j+1)%n;//无穷缓冲区无须’%n’

V(S1);

消费产品;

}}

③环行多缓冲区多生产消费者[书P120]:

同步:

生产者不能往满缓冲区放产品(S1(n));消费者不能从空缓冲区取产品(S2(0))。

n为缓冲区大小。

互斥:

设置指示下一个空缓冲区的位置变量(i(0)),生产者之间互斥(mutex1

(1));设置指示下一个产品在缓冲区的位置变量(j(0)),消费者之间互斥(mutex2

(1))。

也可以生产者和消费者之间都互斥(把mutex1和mutex2都换成一个mutex

(1))。

voidProducer()

{

while(true){

生产一个产品;

P(S1);申请一个空的缓冲区

P(mutex1);一个生产者申请制造产品

放到缓冲区;

i=(i+1)%n;指针移动到下一空的缓冲区

V(mutex1);释放生产者

V(S2);释放一个满的缓冲区

}}

voidConsumer()

{

while(true){

P(S2);申请一个满的缓冲区

P(mutex2);一个消费者申请消费

从第j个缓冲区取一个产品;

j=(j+1)%n;指向下一个满的缓冲区

V(mutex2);释放消费者

V(S1);释放一个空的缓冲区

消费产品;

}}

④用进程通信(信箱通信)的方法解决上述问题[习题P175-27]:

voidProducer()

{

msgbuffmb;//messagebuffer

while

(1){

generatesth.tosend;

receive(consumer,&mb);//取一空缓冲区

create_message(&mb);//放产品到缓冲区

send(consumer,&mb);//生产好的产品发给消费者

}}

//send和receive原语见信箱通信问题

voidConsumer()

{

msgbuffmb;//emptymessage

for(inti=0;i

send(producer,&mb);//初始化,发n个空缓冲区给生产者

while

(1){

receive(producer,&mb);//收到一个产品

extractmessage;//把产品保存下来

send(producer,&mb);//把空缓冲区再发给生产者

dosth.;//消费产品

}}

⑤进程消息缓冲通信[书P128]:

问题:

发送进程把缓冲区中的消息挂到接收进程的消息链上。

同步:

发送进程发送消息数量不限,无消息时接收进程不能取信息,故设置当前消息数量(m-syn(0))。

互斥:

发送和接收进程互斥访问消息队列首指针m-q,故设置互斥信号量(m-mutex

(1))。

   空缓冲区个数为(s-b(n)),设置互斥访问信号量(b-mutex

(1))。

send(R,M)//把消息M发给R

{

找到接收进程R,否则错误返回;

申请缓冲区P(s-b);

P(b-mutex);

取一空缓冲区;

V(b-mutex);

把信息M复制到空缓冲区;

P(m-mutex);

把缓冲区挂到m-q上;

V(m-mutex);

V(m-syn);

}

receive(A)//把消息存到地址A

{

P(m-syn);

P(m-mutex);

取一消息复制到A;

V(m-mutex);

P(b-mutex);

释放消息缓冲区;

V(b-mutex);

}

⑥进程信箱通信[书P130,06年秋讲义]:

问题:

发送进程把信息发到信箱中,接收进程随时取信。

同步:

发送进程不能向满信箱中发信(full(0));接收进程不能从空信箱中取信(empty

(1))。

send(N,M)//把信件M发到信箱N中

{

查找信箱N;

P(full);

把M送入信箱N;

V(empty);

}

receive(N,X)//从信箱N中取一封信放到X

{

查找信箱N;

P(empty);

从信箱N中取一封信放到X;

V(full);

}

⑦进程通信多发送接收者问题[习题P174-16]:

问题:

n1个进程通过m个缓冲区向n2个进程发送消息,每个消息所有接收进程都接收一次。

同步:

发送者不能向满缓冲区发信息(mutex_send[m]

(1));

接收者不能从空缓冲区接收信息(mutex_receive[m](0))。

互斥:

设置指示下一个空缓冲区变量(cur(0)),发送进程互斥访问(mutex_cur

(1));

   设置buffer_count[m](0)记录某个缓冲区被读过几次,若某个缓冲区被读过n2次,则可以释放,接收者互斥访问buffer_count(mutex_count[m]

(1))。

阻塞分析:

若接收者试图接收空缓冲区被阻塞在mutex_receive[k]上,则其他要访问同一缓冲区的接收者被堵塞在mutex_count[k]上;若此时发送者向缓冲区k写入信息,则由第一个接收者释放其他接收者。

   若有一发送者被阻塞在mutex_send[cur]上,则其他发送者被阻塞在mutex_cur上。

voidsend()

{

while(true){

P(mutex_cur);

cur=(cur+1)%m;

//若阻塞则表示cur满

P(mutex_send[cur]);

写入buffer[cur];

//cur内容等待被读取

V(mutex_receive[cur]);

V(mutex_cur);

}

}

voidreceive()

{

While(true){

for(inti=0;i

P(mutex_count[i]);

buffer_count[i]++;

if(buffer_count[i]==1)//第一次读,有信息吗?

P(mutex_receive[i]);

//有信息(或已经有人在访问了),释放其他接收者

V(mutex_count[i]);

从buffer[i]中读;

P(mutex_count[i]);

if(buffer_count[i]==n2){//大家都收过一次了

buffer_count[i]=0;//buffer_count恢复初值

V(mutex_send[i]);//释放此缓冲区

}

V(mutex_count[i]);

}

}}

II.读者—写者问题

读者—写者问题与生产者—消费者问题最大区别在于前者不存在同步问题,就是说不考虑读者没有东西读的问题,没有可读的直接“走人”。

而后者如果没有东西消费,就会阻塞等待。

第一类(读者优先)[书P121]:

问题:

写者在写,则其余写者和读者等待;

有读者在读,则其他读者可读,直到没有读者写者才能写。

互斥:

写者之间互斥以及所有读者和写者之间互斥(write(0/1));读者之间不互斥;

readcount记录当前读者个数(readcount(0)),多个读者对readcount互斥访问,访问后加上1(mutex

(1));readcount是一个可被多个读者进程访问的临界资源,所以需要设置一个互斥信号mutex

阻塞分析:

当有读者在读时,所有写者堵塞在write上;有写者在写时,第一个读者阻塞在write上,其余的阻塞在mutex上,所有写者阻塞在write上。

voidReader()

{

P(mutex);一开始,读者申请一个位置去看书

readcount++;然后逐渐有更多的读者读书,自动加上1

if(readcount==1)//第一个读者,可能有写者在写

P(write);为写者申请一个空间写东西

V(mutex);读者要释放空间或缓冲区了

P(mutex);为读者申请能读书的资源

readcount--;读者读不到足够的书读者逐渐减少

if(readcount==0)//没有读者了,释放写者

V(write);

V(mutex);释放读者,让作者写书

}

voidWriter()

{

P(write);

写;

V(write);//释放的可能是读者或写者

}

/*相对读者优先,即写者可以释放写者;也可改为绝对读者优先,即只要有读者在,写者写完优先释放读者。

方法类似于写者优先。

*/

第二类(写者优先)[习题P175-24]:

问题:

写者在写,则其余写者和读者等待;写者写完,优先释放下一个写者;

读者在读,若无写者等待,则其他读者可读;读者在读,若有写者等待,则其他读者等待。

互斥:

写者之间互斥(write

(1)),读者和写者之间互斥(read

(1));读者之间不互斥;

记录当前读者个数(readcount(0))和写者个数(writecount(0)),读者对readcount互斥访问(mutex1

(1)),写者对writecount互斥访问(mutex2

(1));

为保证在有读者等待的时候,新写者到来也优先释放写者,让等待的读者继续等待,不能将读者和写者阻塞在同一队列上(mutex3

(1))。

阻塞分析:

当有写者在写时,其余写者阻塞在write上,第一个读者阻塞在read上,其他的读者堵塞在mutex3上。

当一个写者写完后,若有写者等待,则唤醒一个写者,否则唤醒第一个读者,由第一个读者唤醒其余读者。

当有读者在读时,一读者R通过P(read)还未V(read),此时新到来的第一位写者W阻塞在read上,其余写者阻塞在mutex2上;新到来的第一位读者R1阻塞在read上,其余读者阻塞在mutex3上:

(1)若正在等待的第一位写者W先于读者R1到来,则他先被读者R释放,接着W会释放其余写者,使原阻塞在mutex2上的写者通过mutex2,重新阻塞在write上,而所有等待的读者仍然阻塞在原来的地方;

(2)否则读者R先释放读者R1,R1代替R的位置,原来等待在mutex3上的第一位读者R2被阻塞在read上,但此时R2在read等待队列上必处于写者W之后,成为情况

(1)。

因此可以看到,在下面的方案中,新写者到来后,最多再放行一位读者。

voidReader()

{

P(mutex3);//若去掉则读者和写者先来后到

P(read);

P(mutex1);//其实有了read无需mutex1

readcount++;

if(readcount==1)

P(write);

V(mutex1);

V(read);

V(mutex3);

reading;

P(mutex1);

readcount--;

if(readcount==0)

V(write);

V(mutex1);

}

voidWriter()

{

P(mutex2);

writecount++;

if(writecount==1)

P(read);

V(mutex2);

P(write);

writing;

V(write);

P(mutex2);

writecount--;

if(writecount==0)

V(read);

V(mutex2);

}

III.哲学家就餐问题

[书P122,06年秋讲义]

问题:

n个哲学家,n支筷子,仅当一个哲学家两边的筷子都可用时才可以拿筷子。

互斥:

设置n个哲学家的状态变量(state[n](thinking/hungry/eating),初始值全thinking),用于判断一个哲学家的左右筷子是否能用;设置n个信号量(s[n],初始全0),用于判断哲学家是否能吃饭。

每个哲学家对state和s互斥访问(mutex

(1))。

voidtest()

{

if(state[i]==hungry&&

state[(i-1)%n]!

=eating&&

state[(i+1)%n]!

=eating)

{//能吃饭,后面的P(s[i])不会阻塞

state[i]=eating;

V(s[i]);

}

}

voidPhilosopher(inti)

{

Thinking;

P(mutex);

state[i]=hungry;

test(i);//能吃饭吗?

V(mutex);

P(s[i]);//能吃饭!

其对应的V操作在test里

拿起左右筷子吃饭;吃完放下左右筷子;

P(mutex);

state[i]=thinking;

//吃完了,帮忙看看左右的能吃饭吗

test((i-1)%n);

test((i+1)%n);

V(mutex);

}

 

IV.爱睡觉的理发师问题

单理发师[习题P174-18,01、06年试题,06年秋讲义]

问题:

理发师只在理发椅前,要么理发要么睡觉;理发师睡觉时,第一个顾客唤醒理发师;理发师在理发时,其余顾客在n张椅子上等待;椅子不够时,顾客离开。

同步:

没有顾客时理发师不能理发,只能睡觉(customer(0));理发师睡觉的时候顾客不能理发,需先唤醒(barber

(1))。

互斥:

设置变量wait_count(0)来记录当前等待的顾客数,理发师和顾客以及顾客之间对其互斥访问(mutex

(1))。

voidBarber()

{

while(true){

P(customer);//有顾客吗?

没有就睡觉

P(mutex);//来顾客了!

//进私室理发,把椅子让给其他人

wait_count--;

V(mutex);

cuthair;

//理完了一个,可以理下一个了

V(barber);

}//注意:

如果barber初值是0,则

}//   V(barber)在cuthair之前

voidCostumer()

{

P(mutex);//防止两顾客同坐最后一个椅子

if(wait_count

wait_count++;//有椅子做,不走了

V(mutex);

V(costumer);//我要理发!

叫醒理发师

P(barber);//理发师忙吗?

忙就等一会

gethaircut;

}

else//没有椅子了,不剪了

V(mutex);

}

银行叫号系统或多理发师问题[习题P174-20,2000年试题]

问题:

银行有n个柜台,每个顾客进入银行取号,若没有空闲柜台则等待,只要有柜台的人员空闲,就叫号。

没有顾客时,柜台人员等待。

同步:

没有顾客时柜台等待(client(0)),无空闲柜台时顾客持号等待(clerk(n))。

互斥:

设置各柜台状态变量(state[n](available/unavailable),初始值全available),任何顾客或柜员均对其互斥访问(mutex

(1))。

voidClerk(inti)

{

while(true){

P(client);//有顾客吗?

办理业务;

P(mutex);//办理完了,恢复状态

state[i]=available;

V(mutex);

V(clerk);//叫下一位顾客

}

}

voidClient()

{

P(clerk);//有空柜台吗?

P(mutex);//找一个空闲柜台

for(intk=1;k<=n;++k){

if(state[k]==available){

state[k]=unavailable;

break;

}//if

}//for

V(mutex);

V(client);//我来啦!

我要取钱!

在第k个柜台办理业务;

}

 

V.音乐爱好者问题

[习题P174-19,99年试题,06年秋讲义]

问题:

三个musiclover各有walkman、CD、battery,三样齐全才能听音乐;老板一次只借出三样中的任何两样,收回后才再次借出。

同步:

没有musiclover老板不能借出东西(musiclover(0));没有东西musiclover不能听音乐,设置no_wc(0)、no_cb(0)、no_bw(0)表示没有三样东西的其中两样。

voidboss()

{

While(true){

intprov=genprovide();//借出某两种

if(prov==1)

V(no_wc);

elseif(prov==2)

V(no_cb);

else

V(no_bw);

P(musiclover);//有人来借prov吗/还了才能借

}}

voidmusiclover(loveri)

{

while(true){

if(i==battery){

P(no_wc);拿到东西,听音乐;}

elseif(i==walkman){

P(no_cb);拿到东西,听音乐;}

else{

P(no_bw);拿到东西,听音乐;}

V(music_lover);//听完了,还给老板

}

}

VI.船闸问题

[习题P174-20,98、03年试题,06年秋讲义]

问题:

A、B两地船只单向通过T级船闸的问题。

互斥:

设置记录A到B和B到A的方向船只个数(A2B_count(0),B2A_count(0)),两个方向的船只互斥访问(mutexA

(1),mutexB

(1))。

再设置船闸信号量(lock

(1)),用于开关船闸。

voidshipA()

{

P(mutexA);

A2B_count++;

if(A2B_count==1)

P(lock);

V(mutexA);

通过船闸;

P(mutexA);

A2B_count--;

if(A2B_count==0)

V(lock);

V(mutexA);

}

shipB和shipA类似,将所有A、B互换就行

这是北大习题课答案。

双向通航问题限制条件多而易变,此处不再讨论。

若限制T级船闸只能过T只船,则需增加一个信号量(max_count_mutex(T))。

voidshipA()

{

P(mutexA);

A2B_count++;

if(A2B_count==1)

P(lock);

V(mutexA);

P(max_count_mutex);

通过船闸;

V(max_count_mutex);

P(mutexA);

A2B_count--;

if(A2B_count==0)

V(lock);

V(mutexA);

}

VII.红黑客问题

[2004年试题]

问题:

船每次坐

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 求职职场 > 简历

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1