操作系统PV原语.docx
《操作系统PV原语.docx》由会员分享,可在线阅读,更多相关《操作系统PV原语.docx(32页珍藏版)》请在冰豆网上搜索。
操作系统PV原语
P(sem)的意思是sem-=1;如果此时sem>=0,说明本次资源请求可以满足,p操作可以返回,执行该进程下面的语句;如果此时sem<0,说明本次资源请求不能满足,进入等待队列,然后转进程调度执行其他进程。
V(sem)的意思是sem+=1;如果此时sem>0,说明没有其他进程在等待该资源,v操作可以返回;如果sem<=0,说明未加1前sem<0,即有其他进程在等待这个刚刚释放的资源,于激活等待队列里一个等待该资源的进程,然后v操作也返回。
Sem>=0时表示剩余资源的数量,Sem<0时表示等待该资源的进程的个数。
注意信号量只能放在P或V操作中,用于加减或其他操作都是错误的,另外对同一信号量,P、V操作次数要相等。
1.p1—p6是并发进程,关系如图
完整C语言代码
信号量fi表示Pi已完成,初始值都是0(表示均未完成)
Semaphoref1=0,f2=0,f3=0,f4=0,f5=0,f6=0;
main()
{
cobegin
p1();
p2();
p3();
p4();
p5();
p6();
coend
}
P1()
{
其他语句;
V(f1);
}
P2()
{
P(f1);
其他语句;
V(f1);
V(f2);
}
P3()
{
P(f1);
其他语句;
V(f1);
V(f3);
}
P4()
{
P(f2);
其他语句;
V(f2);
V(f4);
}
P5()
{
P(f2);
其他语句;
V(f2);
V(f5);
}
P6()
{
P(f3);
P(f4);
P(f5);
其他语句;
V(f3);
V(f4);
V(f5);
V(f6);
}
本题写的是完整代码,多数情况下只需要写过程,过程多数属于循环动作,采用死循环。
P、V操作主要用于互斥和同步。
互斥属于间接制约,受资源数量限制;同步属于直接制约,用于控制各过程的前后次序。
2.生产者-消费者问题
一个生产者和一个消费者之间只有同步关系,多个生产者之间还需要用到互斥,多个消费者之间也需要用到互斥
代码如下
存在空单元才可以生产(有地方存),存在满单元才可以消费(有库存取)。
信号量avail代表缓冲区中空单元数量,初值可设为n;full表示满单元数量,初值可设为0;mutex用于互斥,初值为1。
生产者过程
Deposit():
Begin
P(avail)
P(mutex)
送数据入缓冲区某单元
V(mutex)
V(full)
end
消费者过程
remove():
Begin
P(full)
P(mutex)
取缓冲区某单元数据
V(mutex)
V(avail)
end
这两个过程在这里只执行了一次,也可以视题意放在死循环里(多数情况是循环生产和消费)。
另外要注意P操作要考虑次序,用于互斥的P操作多数情况下放后面(不绝对,要自己分析)。
本题中若颠倒次序,会发生死锁(消费者先抢到mutex资源,却没有满单元,生产者虽然有空单元,但却卡在前面对mutex的请求上)
3.读写者问题
多个进程可以同时读某数据(此时不可写),只允许一个进程写数据(此时不可读)。
代码如下:
rc是全局变量,代表读者人数,初值为0;db是信号量,代表允许写,初值为1(只允许1个人写);mutex是信号量,对全局变量要互斥操作,因此使用mutex,初值为1;读者人数达到1就不可写,读者人数为0时可写。
reader():
begin
L1:
P(mutex)
rc=rc+1
if(rc==1)thenp(db)
v(mutex)
读操作
P(mutex)
rc=rc-1
if(rc==0)thenv(db)
v(mutex)
GotoL1
end
writer():
begin
L2:
P(db)
写操作
V(db)
GotoL2
end
以上代码中,如果一直有人在读,那么写永远没有机会,因此可以增加一个信号量w,初始值为1,代表允许新读者进入,这样当有人想执行写时,就不再允许新读者进入,旧读者总有读完离开的时候,这样写就有机会得到执行。
代码如下
reader():
begin
L1:
P(w)
P(mutex)
rc=rc+1
if(rc==1)thenp(db)
v(mutex)
v(w)
读操作
P(mutex)
rc=rc-1
if(rc==0)thenv(db)
v(mutex)
GotoL1
end
writer():
begin
L2:
P(w)
P(db)
写操作
V(db)
V(w)
GotoL2
end
4.哲学家用餐问题
五个哲学家围成一圈,五根筷子放在每人两侧,拿到两根筷子的可以用餐,没拿到足够筷子的只能等别人吃完放下筷子才能得到足够的筷子。
如果不考虑死锁,每个哲学家的用餐过程如下(i表示哲学家的号码(0-4),左手边筷子号为i,右手边筷子号为(i+1)%5,每个筷子都是资源,用信号量表示),i表示哲学家序号,则每人代码如下
pp(i)
begin
p(stick[i])//拿左边筷子
p(stick[(i+1)%5])//拿右边筷子
用餐
V(stick[i])
V(stick[(i+1)%5])
End
根据实际情况,吃饭过程可以不用死循环。
如果程序写成这样,则存在每个人都拿到左边筷子的死锁情况,预防死锁只要破坏以下4条中的1条:
1.互斥2.允许部分分配3.不剥夺4.循环等待
给资源分先后等级(必须先取得等级高的资源,才能去申请下一等级资源),就可以破坏循环等待条件,从而避免死锁。
本题可以让偶数号码的哲学家先申请左手筷子,再申请右手筷子;让奇数号码的哲学家先申请右手筷子,再申请左手筷子。
这样五跟筷子中的0,2,4成了五个人第一步抢夺的筷子,抢到者才能继续申请1,3,把筷子分成两个等级,从而避免了死锁
代码如下
pp(i)
begin
if(imod2==0)thenbegin
p(stick[i])//拿左边筷子
p(stick[(i+1)%5])//拿右边筷子
end
else
begin
p(stick[(i+1)%5])//拿右边筷子
p(stick[i])//拿左边筷子
end
用餐
V(stick[i])
V(stick[(i+1)%5])
End
5.理发师问题
理发馆有1把理发用的椅子,5把等待座椅,顾客进来后如果没人就坐到理发椅上,有人正在理发就坐到等待椅上,如果等待椅也满了就直接离开。
理发师看到理发椅上坐了人就理发,顾客理发完毕就离开。
描述理发师和顾客的行为。
分析顾客和理发师的行为
顾客:
理发师:
(属于循环动作)
顾客数>=6则离开
否则顾客数+1
申请等待椅
申请理发椅
释放等待椅
发现有人坐到理发椅并准备好,就开始理发,告知理发完毕
释放理发椅
离开(顾客数-1)
定义全局变量waiting,用于统计顾客人数,初值为0;定义信号量mutex,对waiting进行操作时起互斥作用,初值为1;定义信号量bchair表示理发椅个数,初值为1;定义信号量wchair表示等待椅个数,初值为5;定义信号量ready表示顾客坐到理发椅后准备好理发,初值为0;定义信号量finish表示理发完毕,初值为0。
Barber():
Begin
L1:
P(ready)
理发
V(finish)
GotoL1
End
Customers():
Begin
L1:
//这里用死循环表示不断有顾客来
P(mutex)
If(waiting<6)thenbegin
Waiting+=1
V(mutex)
Elsebegin
V(mutex)
Return//(离开)
End
P(wchair)//申请等待椅
P(bchair)//申请理发椅
V(wchair)//申请到理发椅后释放等待椅
V(ready)//向理发师发出准备好信号
P(finish)//收到理发师理发完毕信号
V(bchair)//释放理发椅
P(mutex)
Waiting-=1
V(mutex)
Return//(离开)
GotoL1
End
7.P1、P2、P3互斥使用一个N单元的缓冲区,P1用produce()生成一个正整数,用put(x)把该数放入缓冲区某一空单元;P2用getodd()从缓冲区取出一个奇数,用countodd()统计奇数个数;P3用geteven()从缓冲区取出一个偶数,用counteven()统计偶数个数,写出P1、P2、P3。
P1、P2、P3显然和生产者-消费者问题类似,有一个生产者,两个消费者,消费产品的类型不同,因此生产时也要区分产品类型,并且这3个进程可以写成死循环。
定义信号量empty,表示空单元个数,初值为N;定义信号量odd表示放奇数单元的个数,初值为0;定义信号量even表示放偶数单元的个数,初值为0;定义信号量mutex,用于实现缓冲区互斥,初值为1。
P1():
Begin
L1:
x=produce()
p(empty)
p(mutex)
put()
v(mutex)
ifx%2=1thenv(odd)
elsev(even)
gotoL1
end
P2():
Begin
L2:
P(odd)
P(mutex)
Getodd()
v(mutex)
v(empty)
countodd()
gotoL2
end
P3():
Begin
L3:
P(even)
P(mutex)
Geteven()
v(mutex)
v(empty)
counteven()
gotoL3
end
8.过桥者问题,
同方向可上桥,桥上最多可容纳3个人。
过桥问题类似读写者问题,读写者是一方为多个读者,一方为一个写者,而过桥问题相当于把读者分两组,同组的可进入同时阅读。
定义全局变量easten,westen分别表示桥上从东往西和从西往东的人数,初值为0;定义信号量meast,mwest分别用于桥东头和桥西头用于统计人数时进行互斥,初值均为1;桥上无人时两边不能同时上桥,因此定义信号量wait,用于互斥,初值为1;定义信号量count,用于限制桥上人数,初值为3。
以下为桥两端每个过桥者行为的代码:
easttowest():
begin
P(wait)
P(meast)
easten=easten+1
if(easten==1)thenp(mwest)//桥上只要有一个从东往西的,则禁止西桥头的人上桥
v(meast)
v(wait)
p(count)
东->西
V(count)
P(meast)
easten=easten-1
if(easten==0)thenv(mwest)//桥上没有从东往西的人,则允许西桥头的人上桥
v(meast)
end
另一端程序如下,与之类似
westtoeast():
begin
P(wait)
P(mwest)
westen=westen+1
if(westen==1)thenp(meast)
v(mwest)
v(wait)
p(count)
西->东
v(count)
P(mwest