【高效复习】操作系统——PV重难点

本文详细阐述了操作系统中的PV操作,包括P(S)和V(S)原语的动作,并探讨了读者-写者问题、哲学家用餐问题、理发师问题等经典同步问题。此外,还列举了多个涉及PV操作的复杂场景,适合计算机期末和考研复习。

选自《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);
}

欢迎感兴趣的朋友讨论与指正,原创文章如需转载请注明出处

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值