PV操作解决进程同步问题,生产者消费者问题为例

2024-03-13 12:38

本文主要是介绍PV操作解决进程同步问题,生产者消费者问题为例,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

一、基本概念解释

进程同步:多个进程执行过程中,为了共享资源和相互合作而在执行次序上的协调。

同时也说一下互斥:当某一进程访问某一资源时,不允许其他进程同时访问,这种限制称为互斥。

临界资源:一次只允许一个进程访问的资源称为临界资源。

临界区:进程访问临界资源的程序段。

信号量机制:
信号量机制是1965年荷兰学者Dijkstra提出的,它包含两个标准的原子操作,wait(s)和signal(s),这两个操作又可以被称为P、V操作。在整个操作过程中,P、V必须成对出现。
P(s)基本操作:
s=s-1;
两种情况:1)s>=0,继续操作
2)s<0,中断CPU,保留现场,进程变为阻塞状态,进程的PCB表放入等待队列中。

V(s)基本操作:
s=s+1;
两种情况:1)s>0,继续操作
2)s<=0,从等待队列中唤醒一个进程,变成就绪状态,并将其PCB表插入就绪队列

上面P、V操作的描述对于它们的作用表现的不是很明显,所以这里特别提出:P操作相当于请求资源,所以会有s=s-1;V操作相当于释放资源,所以会有s=s+1; S为系统的资源,当s<0时代表系统资源申请完了,所以后面的进程只能阻塞,也就是说P操作会引起进程阻塞;类比过来,V操作可以解封进程。

二、PV操作解决生产者-消费者问题

(这部分内容是我看到一个博客写的很好,比较容易理解,所以转载过来的)

在理解了PV操作的的含义后,就必须讲解利用PV操作可以实现进程的两种情况:互斥和同步。根据互斥和同步不同的特点,就有利用PV操作实现互斥与同步相对固定的结构模式。这里就不详细讲解了。但生产者-消费者问题是一个有代表性的进程同步问题,要学生透彻理解并不容易。但是如果我们将问题细分成三种情况进行讲解,理解难度将大大降低。

1)一个生产者,一个消费者,公用一个缓冲区。

可以作以下比喻:将一个生产者比喻为一个生产厂家,如伊利牛奶厂家,而一个消费者,比喻是学生小明,而一个缓冲区则比喻成一间好又多。第一种情况,可以理解成伊利牛奶生产厂家生产一盒牛奶,把它放在好又多一分店进行销售,而小明则可以从那里买到这盒牛奶。只有当厂家把牛奶放在商店里面后,小明才可以从商店里买到牛奶。所以很明显这是最简单的同步问题。

解题如下:

定义两个同步信号量:

empty——表示缓冲区是否为空,初值为1。
full——表示缓冲区中是否为满,初值为0。
生产者进程

while(TRUE){生产一个产品;P(empty);产品送往Buffer;V(full);
}

消费者进程

while(true){P(full);从Buffer取走一个产品;V(empty);消费该产品;
}

2)一个生产者,一个消费者,公用n个环形缓冲区。

第二种情况可以理解为伊利牛奶生产厂家可以生产好多牛奶,并将它们放在多个好又多分店进行销售,而小明可以从任一间好又多分店中购买到牛奶。同样,只有当厂家把牛奶放在某一分店里,小明才可以从这间分店中买到牛奶。不同于第一种情况的是,第二种情况有N个分店(即N个缓冲区形成一个环形缓冲区),所以要利用指针,要求厂家必须按一定的顺序将商品依次放到每一个分店中。缓冲区的指向则通过模运算得到。

解题如下:

定义两个同步信号量:

empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。

设缓冲区的编号为1~n-1,定义两个指针in和out,分别是生产者进程和消费者进程使用的指针,指向下一个可用的缓冲区。

生产者进程

while(TRUE){生产一个产品;P(empty);产品送往Buffer(in);in=(in+1)mod n;V(full);

消费者进程

while(TRUE){P(full);从buffer(out)中取出产品;out=(out+1)mod n;V(empty);消费该产品;}

3)一组生产者,一组消费者,公用n个环形缓冲区

第三种情况,可以理解成有多间牛奶生产厂家,如蒙牛,达能,光明等,消费者也不只小明一人,有许许多多消费者。不同的牛奶生产厂家生产的商品可以放在不同的好又多分店中销售,而不同的消费者可以去不同的分店中购买。当某一分店已放满某个厂家的商品时,下一个厂家只能把商品放在下一间分店。所以在这种情况中,生产者与消费者存在同步关系,而且各个生产者之间、各个消费者之间存在互斥关系,他们必须互斥地访问缓冲区。

解题如下:

定义四个信号量:

empty——表示缓冲区是否为空,初值为n。
full——表示缓冲区中是否为满,初值为0。
mutex1——生产者之间的互斥信号量,初值为1。
mutex2——消费者之间的互斥信号量,初值为1。

设缓冲区的编号为1~n-1,定义两个指针in和out,分别是生产者进程和消费者进程使用的指针,指向下一个可用的缓冲区。

生产者进程

while(TRUE){生产一个产品;P(empty);P(mutex1);产品送往buffer(in);in=(in+1)mod n;V(mutex1);V(full);}

消费者进程

while(TRUE){P(full);P(mutex2);从buffer(out)中取出产品;out=(out+1)mod n;V(mutex2);V(empty);}

在上面使用的变量中,关于empty和full变量表示的意义,源博文中的作者说的是empty——表示缓冲区是否为空
full——表示缓冲区中是否为满
根据后面的使用,我个人觉得可以换一个说法:
empty——表示缓冲池中空缓冲区(没有使用的缓冲区)的数量
full——表示缓冲池中满缓冲区(已经使用的缓冲区)的数量

参考文章链接:https://blog.csdn.net/u014174955/article/details/44022391

这篇关于PV操作解决进程同步问题,生产者消费者问题为例的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/804905

相关文章

JAVA Calendar设置上个月时,日期不存在或错误提示问题及解决

《JAVACalendar设置上个月时,日期不存在或错误提示问题及解决》在使用Java的Calendar类设置上个月的日期时,如果遇到不存在的日期(如4月31日),默认会自动调整到下个月的相应日期(... 目录Java Calendar设置上个月时,日期不存在或错误提示java进行日期计算时如果出现不存在的

Mybatis对MySQL if 函数的不支持问题解读

《Mybatis对MySQLif函数的不支持问题解读》接手项目后,为了实现多租户功能,引入了Mybatis-plus,发现之前运行正常的SQL语句报错,原因是Mybatis不支持MySQL的if函... 目录MyBATis对mysql if 函数的不支持问题描述经过查询网上搜索资料找到原因解决方案总结Myb

Nginx错误拦截转发 error_page的问题解决

《Nginx错误拦截转发error_page的问题解决》Nginx通过配置错误页面和请求处理机制,可以在请求失败时展示自定义错误页面,提升用户体验,下面就来介绍一下Nginx错误拦截转发error_... 目录1. 准备自定义错误页面2. 配置 Nginx 错误页面基础配置示例:3. 关键配置说明4. 生效

Java调用DeepSeek API的8个高频坑与解决方法

《Java调用DeepSeekAPI的8个高频坑与解决方法》现在大模型开发特别火,DeepSeek因为中文理解好、反应快、还便宜,不少Java开发者都用它,本文整理了最常踩的8个坑,希望对... 目录引言一、坑 1:Token 过期未处理,鉴权异常引发服务中断问题本质典型错误代码解决方案:实现 Token

MySQL游标和触发器的操作流程

《MySQL游标和触发器的操作流程》本文介绍了MySQL中的游标和触发器的使用方法,游标可以对查询结果集进行逐行处理,而触发器则可以在数据表发生更改时自动执行预定义的操作,感兴趣的朋友跟随小编一起看看... 目录游标游标的操作流程1. 定义游标2.打开游标3.利用游标检索数据4.关闭游标例题触发器触发器的基

springboot3.x使用@NacosValue无法获取配置信息的解决过程

《springboot3.x使用@NacosValue无法获取配置信息的解决过程》在SpringBoot3.x中升级Nacos依赖后,使用@NacosValue无法动态获取配置,通过引入SpringC... 目录一、python问题描述二、解决方案总结一、问题描述springboot从2android.x

在C#中分离饼图的某个区域的操作指南

《在C#中分离饼图的某个区域的操作指南》在处理Excel饼图时,我们可能需要将饼图的各个部分分离出来,以使它们更加醒目,Spire.XLS提供了Series.DataFormat.Percent属性,... 目录引言如何设置饼图各分片之间分离宽度的代码示例:从整个饼图中分离单个分片的代码示例:引言在处理

Python列表的创建与删除的操作指南

《Python列表的创建与删除的操作指南》列表(list)是Python中最常用、最灵活的内置数据结构之一,它支持动态扩容、混合类型、嵌套结构,几乎无处不在,但你真的会创建和删除列表吗,本文给大家介绍... 目录一、前言二、列表的创建方式1. 字面量语法(最常用)2. 使用list()构造器3. 列表推导式

Go异常处理、泛型和文件操作实例代码

《Go异常处理、泛型和文件操作实例代码》Go语言的异常处理机制与传统的面向对象语言(如Java、C#)所使用的try-catch结构有所不同,它采用了自己独特的设计理念和方法,:本文主要介绍Go异... 目录一:异常处理常见的异常处理向上抛中断程序恢复程序二:泛型泛型函数泛型结构体泛型切片泛型 map三:文

Springboot3统一返回类设计全过程(从问题到实现)

《Springboot3统一返回类设计全过程(从问题到实现)》文章介绍了如何在SpringBoot3中设计一个统一返回类,以实现前后端接口返回格式的一致性,该类包含状态码、描述信息、业务数据和时间戳,... 目录Spring Boot 3 统一返回类设计:从问题到实现一、核心需求:统一返回类要解决什么问题?