选自《PV经典》与《天勤》适合计算机期末与考研考试
以下为PV重难点
P(S)原语操作动作:
(1)S减少1;
(2)若S减少1后仍大于或等于零,则进程继续执行。
(3)若S减1后小于零,则该进程被阻塞后进入与该信号相对应队列中,然后转进程调度。
V(S)原语操作动作:
(1)S增加1;
(2)若S增加1后仍大于零,则进程继续执行。
(3)若S增加1后小于零等于零,则该进程信号等待队列中唤醒一个等待进程,然后转进程调度或返回原进程继续执行。
读者-写者问题:
(1)读者优先 (多个读者,一个写者)
定义读者优先:读者要进行读操作时,如果此时正有其他读者在进行操作他可直接开始读操作,而不需等待。
定义一个信号量Readcount:表明读者存在,写者不可进入
Semaphore rmutex=1;
Semaphore mutex=1;
int readcount=0;
reader()
{
While(true)
{
P(rmutex);
If(readcount== 0) p(mutex);
Readcount++;
V(rmutex);
进行读操作;
P(rmutex);
Readcount--;
If(readcount==0)
V(mutex);
V(rmutex);
}
}
Writer()
{
While(true)
{
p(mutex);
写操作;
V(mutex);
}
}
(2)公平情况
引入wmutex:是否有写者在写或等待,后续读者不可进入。
Semaphore mutex=1;
Semaphore rmutex=1,wmutex=1;
int readcount=0;
reader()
{
While(true)
{
P(wmutex); //检测是否有写者进入
P(rmutex);
If(readcount== 0) p(mutex);
Readcount++;
V(rmutex);
V(wmutex);
读操作;
P(rmutex);
Readcount--;
If(readcount==0)
V(mutex);
V(rmutex);
}
}
Writer()
{
While(true)
{
P(wmutex); //检测是否有其他写者,有则等待
P(mutex);
Writing….;
V(mutex);
V(wmutex);
}
}
(3)写者优先
Readable:写者到达时,写者优先进入临界区
Semaphore mutex=1;
Semaphore rmutex=1,wmutex=1;
Semaphore readable=1;
int readcount=0,writercount=0;
reader()
{
P(readable);
P(rmutex);
If(readcount== 0) p(mutex);
Readcount++;
V(rmutex);
V(readable);
Reading…;
P(rmutex);
Readcount--;
If(readcount== 0) v(mutex);
V(rmutex);
}
Writer()
{
While(true)
{
P(wmutex);
If(writecount== 0) p(readable);
Writecount++;
V(wmutex);
P(mutex);
Writing…;
V(mutex);
P(wmutex);
Writecount--;
If(writecount==0) v(readable);
V(wmutex);
}
}
哲学家用餐三种方法:
(1)最多4位(5个人吃)同时用餐;
(2)仅当一位哲学家左右两边筷子可同时拿起;
(3)哲学家编号,奇数号哲学家先拿左边,偶数号先拿右边。
理发师问题(若干生产者与一个消费者)
-简化版,将理发师的椅子和等待用的凳子统一起来
int chairs=n+1;
semaphore ready=0;
semaphore finish=0//理发操作
semaphore mutex=1; // chairs的互斥访问
barber()
{
While(true)
{
P(ready);
理发;
V(finish);
P(mutex);
Chair++;
V(mutex);
}
}
Customer()
{
P(mutex);
If(chairs>0)
{
Chairs--;
V(mutex);
V(ready);
P(finish);
}
Else{
V(mutex);
}
}
以下把PV中的常见难点分为三类:
(1)写法或表达上,由于多进程之间的交互关系,所以有下标或者for循环参与;
(2)读者与写者扩展问题,涉及数值转化、初始赋值讨论以免死锁等;
(3)多资源互斥,涉及一次申请必须全部申请所有资源问题,还有各资源之间同步交替。
一、
1、(PV经典 P28)进程P1,P2通过两缓冲区给进程P11,P12,P21,P22分别传递信息(P11/P12->P1;P21/P22->P2)假定两个缓冲区一样大,所要传递信息与缓冲区一样大,同一时刻只能由一个进程往缓冲区中进行操作(存/取),问:表示6个进程互斥与同步关系。
Semaphore mutex=1,s11=0,s12=0,s21=0,s22=0;
Semaphore empty1=1,empty2=1,full1=full2=0;
Cobegin
Process p1:
While(true){
P(empty1);
P(mutex);
Put buff1;
V(mutex);
V(s11);
V(s12);
V(full1);
}
Process p2:
While(true){
P(empty2);
P(mutex);
Put buff2;
V(mutex);
V(s21);
V(s22);
V(full2);
}
Process sij (i=1,2;j=1,2)
While(true)
{
P(fulli);
P(sij);
Get buffi;
V(mutex);
V(emptyi);
}
Coend;
关于buffer[in]=x; in=(in+1)%n;
2、(PV经典 P47)进程a1……an1通过m个缓冲区向进程b1….bn2不断发送消息。发送和接受工作遵循下列规则:
(1)每个发送进程一次发一个消息,写入一个缓冲区,缓冲区大小等于消息长度。
(2)对每个消息,b1….bn2都须各接受一次,读入各自数据区内;
(3)m个缓冲区满时,进程发送等待,无可读消息时,进程接受等待。
Semaphore sin[n2]=m;sout[n2]=0;
Semaphore mutex=1;
Cobegin
Process aj(j=1…n1)
While(true)
{
for(i=1;i<=n2;i++)
{
P(sin[i]);
P(mutex);
Put buffer;
V(mutex);
}
for(i=1;i<=n2;i++)
V(sout[i]); //必须分开写以保证B进程同时读;
}
Process bi(i=1….n2)
While(true)
{
P(sout[i]);
P(mutex);
Read buffer;
V(mutex);
V(sin[i]);
}
Coend;
3、(PV经典 P59)三个并发进程:r负责输入设备信息块,m负责对信息块加工处理并把处理完的信息块放入另一个缓冲区供p使用,p负责打印输出信息块,其中两个缓冲区各可放k个信息块。
Var a[k-1],b[k-1];
Semaphore sput1=sput2=k; sget1=sget2=0; //记录存放与取出数
Semaphore put1=put2=0; get1=get2=0; //同步机制
Cobegin
Process reader:
While(true)
{
Read x;
P(sput1);
A[put1]=x;
put1=(put1+1)%k;
V(sput1);
}
Process manager
While(true)
{
P(sget1);
X=a[get1];
get1=(get1+1)%k;
v(sput1);
处理信息;
P(sput2)
b[put2]=(put2+1)%k;
v(sget2);
}
Process writer:
While(true)
{
P(sget2);
X=b[get2];
get2=(get2+1)%k;
v(sput2);
}
二、
1、(PV经典 P21)假设buf1与buf2无限大,p1向buf1写数据,p2向buf2写数据,要求buf1和buf2数据个数差保持在(m,n)之间,m<n。
分析:m<|buf1-buf2|<n 本质是一个生产消费问题
不妨 m<=buf1-buf2<=n ,意思是至少有m个空位,至多有n个空位,即emptya=n,emptyb=-m;
Semaphore mutex1=1;mutex2=1;empty=n, full=-m;
P1()
{
While(true)
{
P(empty);
P(mutex1);
Writing…;
V(mutex1);
V(full);
}
}
P2()
{
While(true)
{
P(full);
P(mutex2);
Reading…;
V(mutex2);
V(empty);
}
}
变式:
若改为,-m<=buf2-buf1<=n,则empty1=m,empty2=n;
2、(PV经典 P58)5台类型相同打印机,编号1-5,系统中有n个使用打印机进程,使用前申请,使用后释放,每个进程有一个进程标识,用于区别进程,每个进程有一个优先级。优先级各异且有高到低次序实施分配。
分析:require(pid,pri) pid-进程标识;pri-优先级
返回所申请打印机编号 return(print) print-打印机编号
#define N 5
int flag[N+1]; //flag[0]表示可用打印机数
PCB queue=NULL;// 进程阻塞队列
Semaphore mutex_flag=1;// flag互斥访问
mutex_queue=1;// 阻塞队列互斥
int require(int pid,int pri)
{
P(mutex_flag);
If(flag[0]>0)
{
flag[0]--;
for(int i=1;i<N+1;i++)
if(flag[i]==1)
{
flag[i]=0;
break;
}
V(mutex_flag);
return i;
}
else{
v(mutex_flag);
p(mutex_queue);
pid按pri插入队列;
v(mutex_queue);
}
}
Return (int print)
{
P(mutex_flag);
if(queue==null)
{
flag[0]++;
flag[print]++;
v(mutex_flag);
}
else{
v(mutex_flag);
p(mutex_queue);
将print分配给queue队首;
Queue下移;
}
}
3、(PV经典 P70)三个工人,工人1与工人3,工人2与工人3位生产消费关系,且通过大小为n共同缓冲区相联,其中工人1生产车架,工人2生产车轮,一个车架与两个车轮均由工人3组装出一辆车。
Semaphore empty=n,frame=0,wheel=0,mutex=1; //empty用于总个数统计,是s1和s2是分别算车架和车轮数
Semaphore s1=n-2; s2=n-1;//起限制作用,防止极端情况下工人1、2、3死锁
int in1=0,in2=n-1; int buf[n];
p1()
while(true)
{
生产车架;
P(empty);
P(s1)
P(mutex);
Buf[in1]=车架;
in1=in1+1;//由于相互同步可不用循环
v(mutex);
v(frame);
}
P2()
while(true)
{
生产轮;
P(empty);
P(s2);
P(mutex);
Buf[in2]=车轮;
in2=in2-1;//由于相互同步可不用循环
v(mutex);
v(wheel);
}
P3()
while(true)
{
P(frame);
P(mutex);
in1--;
temp1=buf[in1];
v(mutex);
v(s1);
v(empty);
P(wheel);
P(wheel);
P(mutex);
in2++;
temp2=buf[in2];
in2++;
temp2=buf[in2];
v(mutex);
v(s2);
v(s2);
v(empty);
v(empty);
组装;
}
三、
1、(PV经典 P37)一条公路两次横跨运河,两个运河桥相距100m,均带闸门,以供船支通行。运河和公路交通均是单向,运河上运输由货船担负,在货船接近吊桥A时拉汽笛警告,若桥上无车辆,吊桥就吊起直到船尾P通过此桥为止。对吊桥B也按同样的次序处理,一般典型货船长200m,问怎样的P/V可以防止航行时死锁。

分析:船体大于100m,以防出现船头过了A要到B时,在B端有小汽车无法升起吊桥的极端情况,必须同时申请两段吊桥。
Semaphore sa=sb=1;
Cobegin
Process ship
{
P(sa);
P(sb);
Pass;
V(sb);
V(sa);
}
Process car
{
P(sa);
P(sb);
Pass;
V(sb);
V(sa);
}
Coend
2、(PV经典 P31)一条弯曲路段,每次路段指允许一辆自行车通过,如图。但中间有小的安全岛M(同时允许两辆车)可供两辆车在已进入两端进行错车,设计P、V
小心m的申请要提早,m的释放要晚一点(在下一端成功申请之后);
Semaphore tn=1,nt=1,l=1,k=1,m=2;
Cobegin
Process bike-tn
{
While(true)
{
P(tn);
p(l );
t->l;
l->m;
p(m);
v(l);
pass m;
p(k);
v(m);
k->n;
v(k);
v(tn);
}
}
coend
Process bike-nt
{
While(true)
{
P(nt);
p(k);
n->k;
k->m;
p(m);
v(k);
pass m;
p(l);
v(m);
l->t;
v(l);
v(nt);
}
}
变式:(PV经典 P42)多组进程间的交互,要点:同步量内加入其它进程同步量可实现多进程交互。
3、(PV经典 P50) 把学生和监考老师都看作进程,学生有n个人,老师1个人,考场门口每次只能进出一个人,进考场原则是先来先进,当n个学生都进入考场后,教师才能发试卷。学生交卷后可以离开考场,教师要拿全部试卷收齐封装后才可离开。
分析:1.互斥进门(师、生)2.人齐发卷(同步)3.收齐可离开(同步) 本质是写进程优先-本题是两个而已!
Semaphore door=1;stuready=0;
Semaphore exambegin=0;stunum=0;mutex1=1;
Semaphore examover=0;stupaper=0;mutex=1;
Process stu
while(true)
{
P(door);
进门;
V(door);
P(mutex1);
Stunumber++;
If(stunumber== n) v(stuready);
V(mutex1);
P(exambegin);
Writing…;
P(mutex);
Stunumber++;
If(stunumber== n) v(examover);
V(mutex);
P(door);
离开;
V(door);
}
Process teacher
while(true)
{
P(door);
进门;
V(door);
P(stuready);
发卷;
V(exambegin);
P(examover);
封卷;
P(door);
离开;
V(door);
}
欢迎感兴趣的朋友讨论与指正,原创文章如需转载请注明出处
本文详细阐述了操作系统中的PV操作,包括P(S)和V(S)原语的动作,并探讨了读者-写者问题、哲学家用餐问题、理发师问题等经典同步问题。此外,还列举了多个涉及PV操作的复杂场景,适合计算机期末和考研复习。
1358

被折叠的 条评论
为什么被折叠?



