用P,V操作解决进程同步问题的解题步骤(优化版)

news2024/11/26 8:57:52

蓝颜色是格外注意的

在这里插入图片描述

在这里插入图片描述
还有读读共享,读写互斥问题。
要背会四个模式,套用模式




在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

例题讲解


1)生产者-消费者问题
一般意义的“生产者—消费者”问题:N个buffer,多个生产者,多个消费者,循环存取buffer。这就是一般意义的“生产者—消费者”问题。利用记录型信号量解决一般意义的“生产者—消费者”问题算法描述,请看教材。
说明:
(1)由于buffer有N个,而且buffer又是临界资源,因此,需要增加一个信号量mutex来实现对buffer的互斥访问,其初始值为1。需要特别强调的是,这种情况下,mutex不能省略。
(2)这种情况下,只要保证为不同的进程分配不同buffer,putdata和getdata操作是可以同时进行的,因此,对buffer的互斥访问不是发生在对buffer的存取操作上,而是发生在对buffer的分配上。








2)“哲学家进餐”问题
教材中解决哲学家进餐问题的算法有可能发生死锁,为避免死锁,可以采用以下三种策略:
策略一原理:至多只允许四个哲学家同时进餐,以保证至少有一个哲学家能够进餐,最终总会释放出他所使用过的两支筷子,从而可使更多的哲学家进餐。定义信号量count,只允许4个哲学家同时进餐,这样就能保证至少有一个哲学家可以就餐。
semaphore chopstick[5]={11111};
semaphore count=4;
void philosopher(int i){
	while(true){
		think();
		wait(count); //请求进入房间进餐
		wait(chopstick[i]); //请求左手边的筷子
		wait(chopstick[(i+1)%5]); //请求右手边的筷子
		eat();
		signal(chopstick[(i+1)%5]); //释放右手边的筷子
		signal(chopstick[i]); //释放左手边的筷子
		signal(count); //退出房间释放信号量
	}
}



策略二原理:仅当哲学家的左右两支筷子都可用时,才允许他拿起筷子进餐。可以利用AND 型信号量机制实现,也可以利用信号量的保护机制实现。利用信号量的保护机制实现的思想是通过记录型信号量mutex对取左侧和右侧筷子的操作进行保护,使之成为一个原子操作,这样可以防止死锁的出现。描述如下:
semaphore mutex = 1 ;
semaphore chopstick[5]={11111};
void philosopher(int i){
	while(true){
		think();
		wait(mutex);
		wait(chopstick[(i+1)%5]);
		wait(chopstick[i]);
		signal(mutex);
		eat();
		signal(chopstick[(i+1)%5]);
		signal(chopstick[i]);
	}
}



策略三原理:规定奇数号的哲学家先拿起他左边的筷子,然后再去拿他右边的筷子;而偶数号的哲学家则相反。按此规定,将是12号哲学家竞争1号筷子,34号哲学家竞争3号筷子。即五个哲学家都竞争奇数号筷子,获得后,再去竞争偶数号筷子,最后总会有一个哲学家能获得两支筷子而进餐。
semaphore chopstick[5]={11111};
void philosopher(int i){
	while(true){
		think();
		if(i%2 == 0){ //偶数哲学家,先右后左。
			wait (chopstick[(i + 1)%5]) ;
			wait (chopstick[i]) ;
			eat();
			signal (chopstick[(i + 1)%5]) ;
			signal (chopstick[i]) ;
		}
		else{ //奇数哲学家,先左后右。
			wait (chopstick[i]) ;
			wait (chopstick[(i + 1)%5]) ;
			eat();
			signal (chopstick[i]) ;
			signal (chopstick[(i + 1)%5]) ;
		}
	}
}









3)“读者—写者”问题的演变
从本质上讲,读者—写者问题要解决:读、读共享;写、写互斥;写、读互斥。有两种解决模式:
模式一,读者优先的“读者—写者”问题解决模式(算法描述请参考教材):
①定义互斥信号量wmutex,实现写、写互斥和写、读互斥。
②定义整型变量Readcount表示正在读的进程数目。由于只要有一个Reader进程在读,便不允许Writer进程写,因此仅当Readcount=0,即无Reader进程在读时,Reader才需要执行Wait(wmutex)操作。若Wait(wmutex)操作成功,Reader进程便可去读,相应地,做Readcount+1操作。同理,仅当Reader进程在执行了Readcount减1操作后其值为0时,才需执行signal(wmutex)操作,以便让Write进程写。
③由于Readcount为多个读进程共享(修改),因此需要以互斥方式访问,为此,需要定义互斥信号量rmutex,保证读进程间互斥访问Readcount。
说明:在读者—写者问题中,实现“读、读共享”是有一定难度的,请掌握该模式(由②和③构成)。
模式二,写者优先的“读者—写者”问题解决模式,算法描述如下:
设3个信号量:
rmutex --- 读互斥信号量,初值为1;
wmutex --- 写互斥信号量,初值为1;
s --- 用于在写进程到达后封锁后续的读者,初值为1;
count --- 共享变量,用于记录当前正在读文件的读者数目,初值为0;
semaphore rmutex=1, wmutex=1, s=1;
int count=0;
main() 
{
	Cobegin
	Reader();
	Writer();
	Coend
}
	Reader(){
		While(1){
			P(s);  
			P(rmutex);
			If (count==0) P(wmutex);  /*当第1个读者读文件时,阻止写者写*/
			count++
			V(rmutex);
			V(s);
			读文件;
			P(rmutex);
			count--;
			If (count==0) V(wmutex);  /*当最后1个读者读完文件时,允许写者写*/
			V(rmutex);
		}
	}
	Writer(){
		While(1){
			P(s);
			P(wmutex);
			写文件;
			V(wmutex);
			V(s);
		}
	}
}





例题解析
【例1】 桌上有1空盘,允许存放1个水果。爸爸向盘中放苹果,也可以向盘中放桔子。儿子专等吃盘中的桔子,女儿专等吃盘中的苹果。规定当盘空时一次只能放1个水果供吃者取用。请用Wait()Signal()原语实现爸爸、儿子、女儿三个并发进程的同步。
【南京大学2000】
【分析】这是复杂情况的“生产者—消费者”问题,既有同步又有互斥。爸爸进程与儿子进程、女儿进程需要同步,儿子进程与女儿进程需要互斥。设置4个信号量S(盘子是否为空,初值为1)、So(盘中是否有桔子,初值为0)、Sa(盘中是否有苹果,初值为0)和mutex(用于对盘子的互斥访问,初值为1)。由于只有一个盘子(相当于只有一个buffer),对盘子的互斥访问发生在对盘子的存取操作上,S、So和Sa就可以保证对盘子的互斥操作了,故mutex也可以省略。
解:设三个信号量:
S --- 盘子是否为空,初值为1;
So --- 盘中是否有桔子,初值为0;
Sa --- 盘中是否有苹果,初值为0;

Semaphore S=1, So=0, Sa=0;
Main() {
	Cobegin
	Father();
	Son();
	Daughter();
	Coend
}
Father() {
	While(1)  {
	Wait(S);   将水果放入盘中;
	If  (放入的是桔子)  Signal(So);
	Else   Signal(Sa);
	}
}
Son() {
	While(1)  {
	Wait(So);   从盘中取出桔子;Signal(S); 吃桔子;
	}
}
Daughter() {
	While(1)  {
	Wait(Sa);   从盘中取出苹果;Signal(S); 吃苹果;
	}
}



【例2】 如图1所示,有多个PUT操作同时向Buff1放数据,有一个MOVE操作不断地将Buff1的数据移到Buff2,有多个GET操作不断地从Buff2中将数据取走。Buff1的容量为m,Buff2的容量是n,PUT、MOVE、GET每次操作一个数据,在操作的过程中要保证数据不丢失。试用P、V原语协调PUT、MOVE的操作,并说明每个信号量的含义和初值。
 
图1  进程操作图
【分析】这里存在两个一般意义的“生产者—消费者”问题,PUT(生产者)与MOVE(消费者)之间,需要设置三个信号量;MOVE(生产者)与GET(消费者)之间,需要设置三个信号量。PUT进程套用生产者进程即可,MOVE进程只有在Buff1有新数据且Buff2有空闲区的时候才移动数据,GET进程套用消费者进程即可。
答案:设置6个信号量full1、empty1、B-M1、full2、empty2、B-M2,它们的含义和初值如下:
1)	full1表示Buff1是否有数据,初值为02)	empty1表示Buff1有空间,初值为m;
3)	B-M1表示Buff1是否可操作,初值为14)	Full2表示Buff2是否有数据,初值为05)	Empty2表示Buff2有空间,初值为n;
6)	B-M2表示Buff2是否可操作,初值为1<PUT类进程>
 {
	repeat
	P(empty1)/*判断Buff1是否有空间,没有则等待 */     
	P(B-M1)/*是否可操作Buff1*/
	PUT;                 
	V(B-M1)/*设置Buff1可操作标志 */               
	V(full1)/*设置Buff1有数据的标志 */ 
	until false 
}
<MOVE类进程>
 {
	repeat
	P(full1)/*判断Buff1是否有数据,没有则等待*/
	P(empty2)/*判断Buff2是否有空间,没有则等待*/      
	P(B-M1)/*是否可操作Buff1  */
	P(B-M2)/*是否可操作Buff2  */
	MOVE;                 
	V(B-M1)/*设置Buff1可操作标志*/  
	V(B-M2)/*设置Buff2可操作标志*/  
	V(empty1)/*设置Buff1有空间标志*/             
	V(full2)/*设置Buff2有数据标志*/ 
	until false 
}

<GET类进程>
           {
repeat
P(full2)/*判断Buff2是否有数据,没有则等待 */     
P(B-M2)/*是否可操作Buff2*/
GET;                 
V(B-M2)/*设置Buff2可操作标志 */               
V(empty2)/*设置Buff2有空间的标志 */ 
until false
 
【例3】(8分)某银行提供1个服务窗口和10个供顾客等待的座位。顾客到达银行时,若有空座位,则到取号机上领取一个号,等待叫号。取号机每次仅允许一位顾客使用,当营业员空闲时,通过叫号选取1位顾客,并为其服务。顾客和营业员的活动过程描述如下:
cobegin
{
   process 顾客i
   {
      从取号机获得一个号码;
      等待叫号;
      获得服务;
   }

   process 营业员
   {
      while (TRUE)
         {
            叫号;
            为顾客服务;
         }
   }
} coend

请添加必要的信号量和P、V(或wait()signal())操作,实现上述过程中的护持与同步。要求写出完整的过程,说明信号量的含义并赋初值。               【全国统考 2011】

解:
semaphore  emptySeats:=10       //空闲座位数
semaphore  fullSeats:=0          //已占座位数
semaphore  mutex:=1            //顾客使用取号机互斥信号量

cobegin
{
   	process 顾客i
   	{
   		wait(emptySeats);        //获取一个座位
      	wait(mutex);             //占用取号机取号
		从取号机获得一个号码;
		signal(mutex)            //释放取号机
      	signal(fullSeats)         //座位上增加一个顾客
		等待叫号;
		signal(emptySeats);      //释放一个座位
      获得服务;
      
   	}

   process 营业员
   {
      while (TRUE)
         {
            wait(fullSeats);        //座位上减少一个顾客
            叫号;
            为顾客服务;
         }
   }
} coend
讲评:此题为生产者-消费者问题的翻版。课本上的哲学家进餐问题、生产者–消费者问题、读者–写者问题为基础性的进程同步问题,需要认真真正掌握,以此为基础用于解决其他进程同步问题。


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/949123.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

光电水表和脉冲水表有什么区别?

随着科技的不断发展&#xff0c;水表也在不断地更新换代。在众多种类的水表中&#xff0c;光电水表和脉冲水表因其高精度、稳定性能和易于管理等优点&#xff0c;逐渐成为现代家庭的首选。那么光电水表和脉冲水表有什么区别呢?下面就由小编来带大家了解下吧。 一、工作原理上的…

ES是一个分布式全文检索框架,隐藏了复杂的处理机制,核心数据分片机制、集群发现、分片负载均衡请求路由

ES是一个分布式框架&#xff0c;隐藏了复杂的处理机制&#xff0c;核心数据分片机制、集群发现、分片负载均衡请求路由。 ES的高可用架构&#xff0c;总体如下图&#xff1a; 说明&#xff1a;本文会以pdf格式持续更新&#xff0c;更多最新尼恩3高pdf笔记&#xff0c;请从下面…

linux centos7 bash中字符串反向输出

给定一个字符串&#xff0c;如何反向(倒序)输出&#xff1f; 字符串反转的方法&#xff1a;a.对各个字符位置进行循环调换&#xff08;从原字符串左边取出放在新字符串的右边&#xff1b;从原字符串右边取出放在新字符串的左边&#xff09;。b.对各个字符由水平排列转为垂直排…

【第四阶段】kotlin语言的list遍历

package Stage4fun main() {val list listOf(1,2,3,4,5,6,7,8,9)//第一种方式 for()println("第一种方式遍历元素&#xff1a;")for (i in list){print("元素&#xff1a;$i")}println()//第二种方式forEachprintln("第二种方式遍历元素&#xff1a;…

微信短链跳转到小程序指定页面调试

首先说下背景&#xff1a;后端给了短链地址&#xff0c;但是无法跳转到指定页面。总是在小程序首页。指定的页面我们是h5页面。排查步骤如下&#xff1a; 1、通过快速URL Scheme 编译。上部普通编译 下拉找到此选项。 、 2、按照小程序的要求的URL Scheme输入。另外后端给的…

满足每个用户的分析需求,奥威BI数据可视化工具真没吹牛

我们都知道&#xff0c;随着BI商业智能技术的发展&#xff0c;现在做数据可视化分析的效率越来越高&#xff0c;操作难度也越来越低&#xff0c;但真能随时满足每个用户的分析需求&#xff1f;奥威BI数据可视化工具真没吹牛。 在奥威BI数据可视化工具上还真有一种功能可及时且…

20个值得收藏的WebGL性能优化技巧

WebGL 是一项功能强大的技术&#xff0c;允许开发人员使用基于 OpenGL ES 图形标准的 WebGL API 在 Web 浏览器中创建 3D 图形。 然而&#xff0c;由于在 Web 环境的限制下实时渲染 3D 图形的复杂性&#xff0c;优化 WebGL 性能可能具有挑战性。 推荐&#xff1a;用 NSDT编辑器…

微信小程序修改数据,input不能实时回显

场景&#xff1a; 填写发票抬头&#xff0c;填写抬头公司时候&#xff0c;会根据用户输入的内容实时获取相关的公司信息&#xff0c;用户选择搜索出来的公司&#xff0c;这时候 setData,但是数据并没有回显&#xff0c;而是需要再需要点一下屏幕。 解决方案&#xff1a; 原来…

8月24-25日上课内容 第三章 MySQL索引、事务与存储引擎

本章结构 索引介绍 1、索引的概念 索引就是一种帮助系统能够快速查询信息的结构 2、索引的作用 设置索引之后查询速度变快&#xff0c;当表很大或查询涉及到多个表时&#xff0c;可以成千上万倍地提高查询速度 加快表与表之间连接 降低数据库的IO成本 创建唯一索引来保证…

【dart】dart基础学习使用(一):变量、操作符、注释和库操作

前言 学习dart语言。 注释 Dart 支持单行注释、多行注释和文档注释。 单行注释 单行注释以 // 开头。Dart 编译器将忽略从 // 到行尾之间的所有内容。 void main() {// 这是单行注释print(Welcome to my Llama farm!); }多行注释 多行注释以 /* 开始&#xff0c;以 / 结…

KubeFlow组件介绍

kubeflow是一个胶水项目&#xff0c;它把诸多对机器学习的支持&#xff0c;比如模型训练&#xff0c;超参数训练&#xff0c;模型部署等进行组合并已容器化的方式进行部署&#xff0c;提供整个流程各个系统的高可用及方便的进行扩展部署了 kubeflow的用户就可以利用它进行不同的…

合并两个有序的单链表,合并之后的链表依然有序

定义节点 class ListNode {var next: ListNode _var x: Int _def this(x: Int) {thisthis.x x}override def toString: String s"x>$x" } 定义方法 class LinkedList {var head new ListNode(0)def getHead(): ListNode this.headdef add(listNode: Li…

省级专精特新!祝贺旭帆科技荣获安徽省“专精特新”中小企业!

2023年8月&#xff0c;安徽旭帆信息科技有限公司&#xff08;以下简称“旭帆科技”&#xff09;成功荣获2023年度“安徽省专精特新中小企业”荣誉称号&#xff0c;成为具备专业化、精细化、特色化、新颖化的“专精特新”企业。 随着《“十四五”促进中小企业发展规划》的深入实…

mysql 查看 、设置缓冲池 buffer_pool

Mysql 存储引擎 MyIsam 和 Innodb 引擎 myIsam 存储引擎&#xff1a; 只缓存索引&#xff0c;不缓存数据&#xff0c;对应的键缓存参数为 key_buffer_size show variables like ‘key_buffer_size’; set global key_buffer_sizexxxx; 或者 my.ini my.cnf [server] key_buffer…

二三维电子沙盘数字沙盘虚拟现实开发教程第14课

二三维电子沙盘数字沙盘开发教程第14课 很久没有写了&#xff0c;主要前段时间在针对怎么显示高精度的 倾斜数据而努力&#xff0c;现在终于实现了效果不错。以前的版本显示倾斜数据控制不太好。 对了。目前系统暂只支持smart3d生成的kml格式的数据&#xff0c;由专有的录入程…

教你如何做正交表

正交表是一种用于多因素实验设计的表格。它可以帮助我们在尽可能少的试验次数下确定各个因素对结果的影响&#xff0c;从而提高实验效率。接下来将从以下几个方面介绍正交表的相关内容。 一、正交表基本概念 正交表是一种特制的表格&#xff0c;用于多因素实验设计研究。根据正…

马蹄集oj赛(第十次)

目录 2的N次幂 升级版斐波那契数列 个数统计 个数统计2 大斐列 AB problem ​编辑 A-B problem 快速幂 进行一个幂的运算 整数大小比较 2的N次幂 难度&#xff1a;黄金 0时间限制&#xff1a;1秒 巴占用内存&#xff1a;128M 任意给定一个正整数N(N≤100)&#xff0…

Qt6 for Windows 环境搭建(Visual Studio)

作者&#xff1a; 一去、二三里 个人微信号&#xff1a; iwaleon 微信公众号&#xff1a; 高效程序员 在 Windows 中&#xff0c;如果想要开发 Qt 应用程序&#xff0c;可以选择多种方式&#xff1a; Qt Creator MinGW 编译器Qt Creator MSVC 编译器Visual Studio&#xff0…

线上祭奠软件:虚拟纪念与情感表达的新方式

线上祭奠软件作为一种新兴的技术应用&#xff0c;正在改变传统祭奠方式&#xff0c;为人们提供了跨越时空的虚拟纪念和情感表达方式。本文将深入探讨线上祭奠软件的意义、功能与挑战&#xff0c;并思考其对社会和个人的影响。 一、线上祭奠软件的意义&#xff1a; 1.跨…