OS第二章五大经典PV

2021/8/24 我想探知宇宙

OS第二章五大经典PV

题目分析和优化

    • OS第二章五大经典PV
  • 一、PV操作体系框架
  • 二、哲学家进餐(干饭)问题
    • 解法一:暴力破解
    • 解法二:限制人数
  • 读者写者问题
    • 问题一:同类不互斥,异类互斥
    • 问题二:同类互斥,异类不互斥
    • 问题三:变态类(真正的)读者-写者-写优先
    • 解法1:
  • 理发师问题
  • 生产者消费者问题(重点)
  • 综合问题:叫号问题
    • 解法1:设置i、j变量
    • 解法2:PV阻塞等待


一、PV操作体系框架


二、哲学家进餐(干饭)问题

2019年统考真题
问题描述:
有n(n>=3) 名哲学家围坐在一张圆桌边,每名哲学家交替地就餐和思考.在圆桌中心有m(m>=1)个碗,每两名哲学家之间有一根筷子。每名哲学家必须取到一个碗和两侧的筷子后,才能进餐,干饭后将碗和筷子放回原位,继续思考,为尽可能多的哲学家同时进餐,且防止出现死锁现象,进行PV操作和semaphore信号量定义。

解法一:暴力破解

资源全锁:

//定义semaphore信号量
semaphore bowl=n;//n个碗
semaphore chopstick[n];//n只筷子
semaphore mutex=1;//互斥取资源信号量
for(int i=0;i<n;i++)
	chopstick[i]=1;//初始化信号量
Pi(){
     //i号哲学家
	while(1){
     
			思考;
		P(mutex);//互斥访问资源
		if(bowl&&chopstick[i]&&chopstick[(i+1)%n]){
     //左右筷子、婉都有
			P(bowl);//拿碗
			P(chopstick[i]);//拿左筷子
			P(chopstick[(i+1)%n]);//拿右筷子
			V(mutex);//拿完就释放互斥
			哲学家干饭;
			V(bowl);//释放碗
			V(chopstick[i]);//释放左筷子
			V(chopstick[(i+1)%n]);//释放右筷子
		}
		else
			V(mutex);//资源不够释放互斥,满足尽可能多的哲学家同时进餐
	}
}

解法二:限制人数

运用了死锁避免

通过限制限制人数为n-1,取和其他资源的最小值 bowl=min{n-1,m}
如果资源类别>=2是要取所有资源的和n-1个人进餐人数的最小值
赋予最小值的信号量代表了同时进餐的人数
并且将赋予最小值的信号量放在进程的一开始的位置P(bowl);如果资源不满足就会阻塞

semaphore chopstick[n];//n只筷子
semaphore bowl=min{
     n-1,m};//同时进餐的最大人数
for(int i=0;i<n;i++)
	chopstick[i]=1;//初始化信号量
Pi(){
     //i号哲学家
	while(1){
     
		思考;
		P(bowl);//拿碗
		P(chopstick[i]);//拿左筷子
		P(chopstick[(i+1)%n]);//拿右筷子
		干饭;
		V(bowl);//释放碗
		V(chopstick[i]);//释放左筷子
		V(chopstick[(i+1)%n]);//释放右筷子
	}
}


读者写者问题

问题一:同类不互斥,异类互斥

经典问题:同类不互斥,异类互斥 :电影院问题
问题描述:电影院有1,2,3种不同的电影(看不同的电影的人代表不同的进程),任意一时刻只能播放一种电影(放映厅互斥)选择当前正在播放的电影的人可以进入(不限制人数),最后一个观看电影的人结束放映厅的播放,看不同电影的人等待(说明第一个进入的占有放映厅,最后一个释放放映厅)

semaphore room=1;//放映厅
semaphore mutex_1=1;//第一种电影的互斥访问count_1信号量
int count_1=0;//第一种电影的观看人数
semaphore mutex_2=1;//第一种电影的互斥访问count_2信号量
int count_2=0;//第二种电影的观看人数
semaphore mutex_3=1;//第三种电影的互斥访问count_3信号量
int count_3=0;//第三种电影的观看人数
P1(){
     //看第一种影片的人
	P(mutex_1);//互斥访问count_1
		if(count_1==0)//第一人
			P(room);//占有放映厅
		count_1++;//看电影1的人数+1
	V(mutex_1);//访问婉count_1后释放
	看片嘻嘻;
	P(mutex_1);//互斥访问count_1
		count_1--;//走就人数-1
		if(count_1==0)//最后一个观看的人
			V(room);//释放放映厅
	V(mutex_1);//释放count_1
}

P2(){
     //看第二种影片的人
	P(mutex_2);//互斥访问count_2
		if(count_2==0)//第一人
			P(room);//占有放映厅
		count_2++;//看电影2的人数+1
	V(mutex_2);//访问婉count_2后释放
	看片嘻嘻;
	P(mutex_2);//互斥访问count_2
		count_2--;//走就人数-1
		if(count_2==0)//最后一个观看的人
			V(room);//释放放映厅
	V(mutex_2);//释放count_2
}

P3(){
     //看第三种影片的人
	P(mutex_3);//互斥访问count_3
		if(count_3==0)//第一人
			P(room);//占有放映厅
		count_3++;//看电影3的人数+1
	V(mutex_3);//访问婉count_3后释放
	看片嘻嘻;
	P(mutex_3);//互斥访问count_3
		count_3--;//走就人数-1
		if(count_3==0)//最后一个观看的人
			V(room);//释放放映厅
	V(mutex_3);//释放count_3
}

问题二:同类互斥,异类不互斥

经典问题:P100 2.3.7 T19 南开大学弯路问题
问题描述:南开大学与天津大学之间有一条弯路,每次只允许一辆自行车通过,但中间安全岛M可供两端的两辆小车错车OS第二章五大经典PV_第1张图片


NtoT(){
     //从N到T
	入口;
	P(NT);//互斥从N到T只能一辆车
	P(K);//到K路段
	经过M;
	V(K);//释放K路段
	P(L);//申请L路段
	出口;
	V(NT);//通过,释放从N到T的互斥
}

TtoN(){
     //从T到N
	P(TN);//互斥从T到N只能一辆车
	P(L);//到L路段
	经过M;
	V(L);//释放L路段
	P(K);//申请K路段
	出口;
	V(TN);//通过,释放从T到N的互斥
}

问题三:变态类(真正的)读者-写者-写优先

王道OS强化课考试T1王道YYDS
问题描述:
某计算机学院,有男老师、男同学若干,没有女同学。学校运动会期间,老师和同学们都需要换上运动服参加运动。整个学院共用一个更衣室,更衣室很大。但是,老师们比较好面子,不想和别人一起更衣,而男同学们比较无所谓,可以和多个同学一起更衣。
更衣室需要让老师优先使用。请使用P、V操作描述上述过程的互斥与同步,并说明所用信号量及初值的含义。
注意的是本题如果用书上的读者-写者问题-写优先是满足不了让老师优先使用的条件的
因此本题需要用真正的读者-写者-写优先

解法1:

semaphore pri=1;//老师优先级
semaphore enter=1;//允许进入信号量
semaphore mutex_t=1;//老师互斥访问count_t
semaphore mutex_s=1;//学生互斥访问count_s
semaphore room=1;//更衣室互斥信号量
int count_t=0;//老师数
int count_s=0;//学生数
Teacher(){
     //老师
		P(enter);//是否允许进入
		P(mutex_t);//老师互斥访问count_t
			if(count_t==0){
     //第一个老师
				P(pri);//优先进入
			}
			count_t++;//老师数+1;
			V(mutex_t);//释放老师变量count_t互斥信号量
			V(enter);//释放共享
			P(room);//占有更衣室
				更衣室换衣服;
			V(room);//换完衣服释放房间
		P(mutex_t);//老师互斥访问count_t
			count_t--;//老师换完衣服退出更衣室老师数-1
			if(count_t==0){
     //如果老师数为0了则暂时没老师要来
				V(pri);//释放优先级
			}
		V(mutex_t);//释放老师互斥访问count_t
}

Student(){
     //学生
		P(pri);//等待老师
		P(enter);//是否允许进入
		P(mutex_s);//互斥访问学生人数count_s变量
			if(count_s==0){
     //第一个学生
				P(room);//占有更衣室
			}
			count_s++;//学生人数+1
		V(pri);//其他人可申请
		V(mutex_s);//释放学生互斥信号
		V(enter);//进入后释放信号量
		更衣室更衣;
		P(mutex_s);//互斥访问学生人数count_s变量
			count_s--;//更衣完退出更衣室
			if(count_s==0)//最后一个学生更衣
				V(room);//释放更衣室
		V(mutex_s);
	
}

理发师问题

经典问题:(有等待资源-椅子)忙(理发师在忙)则等待,没等待资源(没椅子了就拍屁股走人)
问题描述:理发店理有一位理发师、一把理发椅和n把供等候理发的顾客坐的椅子如果没有顾客,理发师便在理发椅上睡觉一个顾客到来时,它必须叫醒理发师如果理发师正在理发时又有顾客来到,则如果有空椅子可坐,就坐下来等待,否则就离开。

注意这里的if else是为了区分两种情况,一种是有资源,一种是没资源,if(有资源)则申请座位在更改资源变量chair后V(mutex)提高并发度。else 就是顾客到了但是没椅子了就走了直接释放V(mutex)
所以说与读者写者的if是不同的,因为读者写者的if纯粹就是互斥访问count修改count的值代表读者有多少个人,不会因为读者有多少个人就会影响其他读者,而理发师问题的wait变量的大小与chair资源的比较就会影响到其他顾客的行为(是离开还是申请chair)

semaphore consumers=0;//顾客人数
semaphore serve=0;//理发师提供服务
semaphore mutex_w=1;//互斥访问wait
int wait=0;//等待人数
int chairs=n;//椅子数量
Tony(){
     //理发师
	while(1){
     
		P(consumers);//没有顾客就睡觉
		P(mutex_w);//互斥访问wait变量
			wait--;//等待人数-1
		V(mutex_w);//访问完wait就释放
		V(serve);//释放服务
		为顾客服务理发;
	}
}

Consumer(){
     //顾客
	顾客进门;
	P(mutex_w);//互斥访问wait变量
	if(wait<chairs){
     //有椅子则申请椅子
		wait++;//等待人数+1
		V(mutex_w);//访问完wait就释放
		V(consumsers);//通知有顾客来了
		P(serve);//申请服务
		接收服务
	}
	else //没椅子
		V(mutex_w);//释放互斥
}

生产者消费者问题(重点)

思想:同步问题:前V后P 生产者消费者的马甲很多同时有些题目很难
史诗级难题:P98 2.3.7 T10 小和尚打水-大和尚喝水

问题描述:某寺庙有小和尚、老和尚若干,有一水缸,由小和尚提水入缸供老和尚饮用。水缸可容10桶水,水取自同一井中。水井径窄(互斥)每次只能容一个水桶取水。水桶总数为3个。每次入缸取水仅为一桶水,且不可同时进行。试给出有关从缸取水、入水的算法描述

semaphore bucket=3;//水桶个数
semaphore empty=10;//水缸空闲容量
semaphore well=1;//水井互斥取水
semaphore vat=1;//水缸互斥取水/放水
semaphore water=0;水缸有水容量
child(){
     //小和尚
	while(1){
     
		P(empty);//保证水缸中还需加水
		P(bucket);//申请桶
		拿桶;
		P(well);//互斥水井取水
		井中取水;
		V(well);//取完水释放水井
	//P(empty);若在此处加就可能发送死锁,缸中水满,桶全被小和尚拿了,老和尚打不了水
		P(vat);//互斥水缸
		放水入缸;
		V(vat);//释放水缸
		V(water);//释放缸中的一桶水,即缸中加了一桶水
		V(bucket);//还桶;
	}
}
adult(){
     //老和尚
	while(1){
     
		P(water);//保证水缸中有水
		P(bucket);//申请水桶
		拿桶;
	//P(water);可能发生死锁,缸中没水,桶全被老和尚拿了,小和尚没桶到水井打水
		P(vat);//互斥水缸
		缸中取水;
		V(vat);//释放水缸
		喝水;
		V(empty);//释放
		V(bucket);//还桶;
	}
}

此处表明了当有地方多次连续出现P时要考虑前后的关系,以防发生死锁


综合问题:叫号问题

方法:①设置顾客号数i,设置叫号号数j,通过比对i和j来判断
           ②直接用PV操作阻塞

如P97 T7面包师
面包师有很多面包,由n名销售人员推销,每名顾客进店后取一个号,并且等待叫号,当一名销售人员空闲时,就叫下一个号。试设计一个使销售人员和顾客同步的算法。

解法1:设置i、j变量

semaphore mutex_i=1;//互斥访问i变量
semaphore mutex_j=1;//互斥访问j变量
int i=0;//顾客的取号号数
int j=0;//销售人员的叫号号数
consumer(){
     //顾客
	进店;
	P(mutex_i);//互斥取号
		取号;
		i++;//号数加1,下一个顾客的编号
	V(mutex_i);//取完号释放互斥
	等待被叫号;
}

salex(){
     //x号销售人员
	while(1){
     
		P(mutex_j);//互斥访问j
			if(j<i){
     //有顾客
				叫号;
				j++;
				V(mutex_j);//访问完j,释放互斥
				销售服务;
			}
			else
				V(mutex_j);//无顾客,休息
	}
}

解法2:PV阻塞等待

semaphore mutex=1;//互斥取号
semaphore consumers=0;//顾客数
semaphore serve=0;//销售人员提供服务
consumer(){
     
		进店;
	P(mutex);//互斥取号
		取号;
	V(mutex);//释放互斥
	V(consumers);//释放顾客信号量,通知有客人
	P(serve);//申请服务
	接收服务;
}
sale(){
     
	while(1){
     
		P(consumers);//没客人休息
		V(serve);//释放服务
		销售面包,为客户服务;
	}
}

你可能感兴趣的:(408,操作系统)