CHS_09.2.3.6_2+多生产者-多消费者

CHS_09.2.3.6_2+多生产者-多消费者

  • 问题描述
    • 问题分析
    • 如何实现
    • 如何实现
    • 假如我们把盘子的容量设为二
    • 知识回顾

在这个小节中 我们会学习一个多生产者 多消费者的这样一个问题模型

问题描述

在这里插入图片描述

先来看一下问题的描述 假设桌子上面有一个盘子 每次只能向这个盘子里放一个水果

有四个人 父亲 母亲 女儿和儿子 父亲每一次会向盘子里放一个苹果

而女儿专门等着吃盘子里面的苹果 所以如果盘子里有苹果的话 女儿会把

这个苹果给取出并且把它吃掉 另外母亲会专门往盘子里面放橘子

儿子又专门等着母亲把橘子放到盘子里 之后他会把盘子里的橘子给取出并且吃掉

如果说由于这个盘子的容量是只能装一个水果 所以如果父亲把苹果装到了盘子里的话

那么 如果这个苹果还暂时没有被女儿取出 这个时候母亲又包了一个

橘子 并且他尝试把橘子放到这个盘子里 但由于这个盘子里只能装一个水果 所以 这种

这个时候 母亲把橘子放入盘子 这个行为应该被阻止 另外呢 由于儿子只吃橘子 所以此时如果盘子里装的是一个苹果的话 那么如果这个儿子
正在尝试从盘子里取出水果 那这个水果由于不是他想吃的 所以它的这种行为也应该被阻止或者说阻塞

那这个问题 其实我们可以把它抽象为咱们上一个小节学过的生产者 消费者模型 我们可以把

问题分析

在这里插入图片描述

这个盘子看作是一个大小为一初始为空的缓冲区 然后把父亲和母亲看作是两个生产者进程

把女儿和儿子分别看作是两个消费者进程 当然 与上一节所讲的生产者消费者模型不同的是

这个这个小节中的这个例子 这些生产者和这些消费者 他们所生产的东西和他们所消费的东西类型是不一样的

而上个小节我们介绍的例子当中 所有的生产者生产的都是一种东西 而所有的消费者也都是消费同一种东西 所以这就是为什么把这个小节的这个问题称作多生产者多消费者的

原因 所谓的多 不是指多个 应该把它理解为是多类 不同类别的生产者和不同类别的消费者 他们所需要生产的和所需要消费的
这些产品是不一样的
那么这个问题我们怎么用pv操作来解决呢

我们用上个小节学习过的方法来一步一步一次分析 首先我们来看一下这个题目当中所描述的场景
总共有几类进程
很显然 父亲母亲 女儿儿子 他们各属于一类进程

另外呢 他们之间是否存在同步和互斥的关系 之前我们说过

这个题目当中这个盘子 我们可以把它看作是一个缓冲区 而上一节我们聊过

对于缓冲区的访问 一般来说都需要互斥的进行 所以我们需要实现对盘子这种缓冲区的互斥访问

另外 是否存在这种一前一后的同步关系呢 首先

父亲要将苹果放入盘子之后 女儿才能取到苹果 所以父亲进程和女儿进程他们之间有一对同步关系

另外 母亲要把橘子放入盘子之后 儿子才可以取到橘子 所以他们俩之间也存在一对同步关系

第三只有盘子为空的时候 父亲或母亲才可以从 才可以把水果放到盘子当中

而这个地方的盘子为空 这个事件其实既可以由儿子触发 也可以由女儿触发 假如说盘子里放的是橘子 那么盘子为空 这个事件就应该由

儿子来触发 由儿子取走橘子 而如果说盘子里放的是苹果的话 那就应该由女儿取走苹果 然后由女儿来触发 盘子为空这个事件

只有盘子为空这个事件发生之后 才能允许父亲进程或母亲进程往盘子里放入水果

所以女儿和儿子 他们可能会触发一个事件来引发父亲或者母亲

往盘子里 放入水果 那这就是这个题目当中所包含的互斥关系和同步关系

第二步 我们来看一下各个进程之间的pv操作流程大概是什么样的

我们知道实现互斥其实很简单 无非就是在访问这个互斥临界资源的
之前和访问临界资源之后 分别对互斥变量实行一个p操作和一个v操作

而实现同步关系 其实我们之前也说过 我们只需要遵循一个原则 就是所谓的前V后P

也就是前面的这个事件发生了之后 我们需要执行一个V操作

后面的这个事件发生之前 我们需要执行一个p操作 那就是这个样子

那么 对于实现互斥关系来说 我们当然是需要设置一个

初值为一的这种互斥信号量 而对于这些同步关系来说 我们需要根据具体的情况来判断每一个同步变量应该设为多少

父亲进程需要把苹果放入盘子 女儿才能取到苹果 所以我们需要设置一个同步信号量叫做apple用来实现这个同步关系

而由于刚开始盘子里面是没有苹果的 所以我们把这个值设为初始值 设为零

只有父亲对这个同步信号量执行v操作 之后 女儿对这个信同步信号量执行的p操作才不会被阻塞 那同样的 对母亲进程来说 我们也设置一个叫做orange 也就是橘子的一个同步信号量 他的初始值也设为一因为刚开始盘子里面是没有橘

另外呢 只有盘子为空的时候 父亲和母亲才可以放入水果 而刚开始

盘子本来就是空的 所以父亲和母亲在刚开始其实就可以向盘子里放入一个

水果 所以这个地方像这一对同步关系 我们就需要为它设置一个初值为一的同步信号量 用来表示此时盘子是否为空 那么来看一下具体的代码实现 我们总共申明了四个

如何实现

在这里插入图片描述

信号量一个 其中一个是互斥信号量 另外三个是同步信号量 父亲进程和母亲进程做的事情就是不断的准备一个自己的水果

然后再把自己的水果放到盘子里 而女儿进程和儿子进程做的事情就是不断的从盘子中取出自己喜欢的水果 并且把这个水果给吃掉

父亲进程在放入水果之前需要先检查这个盘子是否为空

所以 在苹果放入盘子之前 父亲进程需要对这个信号量进行一个p操作来检查此时盘子中到底还可以放多少个水果

那如果这个苹果已经放入盘子之后父亲进程又需要对

apple这个同步信号量执行一个v操作 用来让apple的值加一

来告诉女儿进程 此时苹果盘子中的苹果数量已经加一了

母亲进程也一样 他在把橘子放入盘子之前需要同样需要对盘子中还可以放多少个水果进行检查

如果说此时这个盘子中已经有别的水果 那么母亲进程会被阻塞 在这个地方会被阻塞

而当母亲进程把橘子放入盘子之后 他同样也需要对orange这个同步信号量执行一个v操作来通知儿子进程 此时盘子当中的橘子数已经加一了

那么女儿进程和儿子进程在取出自己喜欢的水果之前 分别需要检查此时这个盘子当中是否已经有自己喜欢的水果 所以女儿进程是对apple这个信号量执行p操作

儿子进程是对orange这个信号量执行p操作 而女儿进程在从盘子中取出苹果之前需要先检查此时苹果的是盘子中苹果的数量是否足够 如果没有苹果的话 它将被阻塞

而当他把苹果取出之后 又需要对plate这个信号量执行v操作 用来告诉父亲进程和母亲进程 此时盘子已经变空了

那么儿子进程也和女儿进程也类似 只不过是他在检查的时候 是检查盘子当中是否有橘子

那这样的话 我们就实现了咱们在这个图中表示的这些同步关系 另外 我们还需要实现各个进程对盘子这种缓冲区的互斥访问

所以我们在这些进程访问盘子之前 对这个互斥信号量执行一个p操作 访问之后又执行一个V操作 分别是对这个临界区进行加锁和解锁

其他的这些进程也一样 那接下来我们再来考虑一个问题 可不可以不要这个互斥信号量呢

如何实现

在这里插入图片描述

就是这样子 我们把互斥信号量去掉 并且把对互斥信号量的pv操作也都去掉

那我们来分析一下 如果是这样的话 这些进程会怎么并发执行 刚开始

由于apple和orange这两个信号量的数量都为零所以女儿进程和儿子进程无论谁上处理机运行 肯定在执行到这个p操作的时候都会被阻塞

那么 我们假设刚开始是由父亲进程上处理机运行 那么他首先会对盘子这个同步信号量执行一个p操作 由于刚开始这个信号量的值位一也就是说盘子这种资源还足够 所以父亲进程 他可以顺利的跳过这个p操作 然后开始

把苹果放入盘子当中 而这个时候 如果说切换回母亲进程 那么当母亲进程对盘子的信号量执行p操作的时候 由于这个值已经变为了零
盘子这种资源已经不够了 所以母亲进程 在这个时候会被阻塞等待盘子

而当父亲进程把苹果放入盘子之后 他又会对apple这个同步信号量执行一个V操作
这个时候 女儿进程她又会被唤醒
然后从盘子当中取出苹果 之后 女儿进程又会对plate这个同步信号量执行一个V操作

由于之前母亲进程是因为这个信号量而被阻塞的 所以当他执行v操作之后 母亲进程就会被唤醒

之后母亲进程就可以开始顺利的访问这个临界区资源 而当母亲进程在访问盘子这种临界资源的时候

由于plate的值为零然后orange和apple的值也都为零所以除了母亲进程以外 别的这些进程即使上处理机运行 也肯定会被卡在这个p操作 这也就会被阻塞

所以通过刚才的分析 我们会发现 在这个题目当中 我们即使不设置专门的互斥信号量没有mutex

我们依然可以实现这些进程对盘子这种临界区的互斥访问

为什么呢 其实原因在于这个题目当中的这个缓冲区的大小只为一

大家可以自己再尝试分析一下更多的情况 apple orange和plate

这三个同步信号量同一时刻最多只有一个 会是一而这几个进程刚开始都需要对其中的某一个信号量执行p操作 由于这三个同步信号量当中同一时刻最多只有一个的值会是一所以这些进程执行各自

的p操作的时候 最多只有一个进程不会被阻塞 可以顺利的进入这个临界区进行访问

假如我们把盘子的容量设为二也就是这个缓冲区的容量把它设为二的话 会发生什么情况呢

假如我们把盘子的容量设为二

在这里插入图片描述
在这里插入图片描述

假设刚开始盘子就可以放两个水果 那么刚开始父亲进程执行p操作 发现盘子资源足够 所以他可以进入临界区开始访问盘子

母亲进程在执行p操作之后也发现盘子这种资源依然是足够的 所以他同样也会进入这个
临界区对盘子这种临界资源进行访问
所以这就发生了父亲进程和母亲进程两个进程同时访问盘子这种临界资源的情况

那通过上个小节的讲解 我们知道 如果两个生产者进程 他们同时对一个缓冲区进行访问的话 那么有可能会导致数据覆盖的问题

这个地方也一样 因此如果我们在生产者 消费者问题当中遇到了缓冲区大于一的情况 那么我们就必须设置一个互斥信号量
mutex来保证各个进程是可以互斥的访问缓冲区的
而如果缓冲区大小等于一的话 那么我们即使不设置这个互斥信号量 有可能也可以实现互斥访问临界区这个事情 当然这不是绝对的 只是有可能 不

需要设置互斥信号量要具体问题具体分析 如果大家在考试的时候遇到缓冲区大小为一的情况的时候 那么

可以自己分析一下 如果能确定不需要使用互斥信号量的话 那么不设置也可以 但如果来不及仔细分析的话 大家最好是加上这个互斥信号量 因为加上了肯定也没错 不过我们需要注意的是上个小节强调过的那个问题实现互斥的

对于mutex 那个信号量的p操作一定要在实现同步的p操作之后 否则是有可能会引起死锁的

知识回顾

在这里插入图片描述
在这里插入图片描述

这个点大家还能不能回忆起来呢 那么和之前的小节一样 大家也需要体会p v操作这种相关的题目的解题思路

和上个小节介绍的经典的生产者消费者问题不太一样的是 这个小节这个模型是多生产者多消费者

他的同步关系要比之前那个小节所介绍的同步关系要复杂的多 大家需要注意一个事情

在分析这种同步问题的时候 我们不能从单个进程的行为的角度来触发 而需要把这种一前一后的事情
把它看作是两个事件的前后关系
这句话我们不太容易理解 我们直接来看例子

如果说在这个题目当中 我们是从单个进程行为的角度来考虑的话

那么 我们会有这样的结论 首先 从题目当中我们可以知道 如果盘子里边装的是苹果

那么一定要女儿取走苹果之后 母父亲和母亲才可以放入水果

所以 当女儿进程取走苹果之后 可能会导致父亲进程

可以放入水果 同样也可能导致母亲进程 可以放入水果 另外

如果盘子里装的是橘子话 那么儿子取走橘子之后 可能会导致父亲进程可以放入水果 也可能会导致母亲进程可以放入水果

那么如果我们从这个 这种单个进程的行为来分析的话 那仅仅这两句话 我们就可以分析出这样的四个同步关系

那么有四个同步关系是不是就意味着我们要设置四个同步信号量来分别实现这四个一前一后的这种关系了呢

当然不是其实正确的分析方法 我们应该从事件的角度来考虑

我们应该把刚才所描述的这种进程行为的前后关系 也就是 女儿取走

取走水果这个行为导致父亲可以放入水果 同样也导致母亲可以放入水果 从这种行进程行为的前后关系 我们可以把它抽象为一对事件的

前后关系 我们应该把进程同步问题 把它理解为 某一个事件 一定要求发生在另一个事件之前

而不是某一个进程的行为要发生在另一个进程的行为之前 那么我们如果从事件的角度来考虑的话

刚才所描述的这两句话 其实我们可以抽象为两个事件 盘子变空的事件可一定要发生在放入水果这个事件之前

而盘子变空这个事件 既可以由儿子进程来引发 也可以由

女儿进程来引发放水果的这个事件 既可以是父亲进程来执行也可以是母亲进程来执行

所以刚才我们看起来有四对同步关系 其实我们如果把从事件的角度来考虑的话 我们可以把它抽象为一对事件的前后关系

而这些事件可以由哪个进程来引发 那么这个进程就需要对这个事件对应的

同步信号量 执行一个v操作 同样的父亲进程和母亲进程都有可能会执行放入水果这个事件 所以在放他们执行各自的放入水果事件之前

我们需要对这个事件对应的同步信号量执行 分别执行一个p操作

那这个地方大家还需要自己认真的体会 这对于初学者来说确实比较容易犯这样的问题

那如果能把这个部分的内容理解了 以后再做同步相关的这些大题的时候 应该问题就不大了

好的 那么这就是这个小节的全部内容

推荐一个零声学院免费公开课程,个人觉得老师讲得不错,分享给大家:Linux,Nginx,ZeroMQ,MySQL,Redis,fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,TCP/IP,协程,DPDK等技术内容,立即学习

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

搜索专项---Flood Fill

文章目录 池塘计数城堡问题山峰与山谷 一、池塘计数OJ链接 1.BFS做法 #include <bits/stdc.h>#define x first #define y secondtypedef std::pair<int,int> PII;constexpr int N1010;int n,m; char g[N][N]; bool st[N][N];//用来表示已经记录过的 std::queue&…

3D力导向树插件-3d-force-graph学习002

一、实现效果&#xff1a;节点文字同时展示 节点显示不同颜色节点盒label文字并存节点上添加点击事件 二、利用插件&#xff1a;CSS2DRenderer 提示&#xff1a;以下引入文件均可在安装完3d-force-graph的安装包里找到 三、关键代码 提示&#xff1a;模拟数据可按如下格式填…

笔记---容斥原理

AcWing,890.能被整除的数 给定一个整数 n n n 和 m m m 个不同的质数 p 1 , p 2 , … , p m p_{1},p_{2},…,p_{m} p1​,p2​,…,pm​。 请你求出 1 ∼ n 1∼n 1∼n 中能被 p 1 , p 2 , … , p m p_{1},p_{2},…,p_{m} p1​,p2​,…,pm​ 中的至少一个数整除的整数有多少…

SemiDrive E3 MCAL 开发系列(1) – 环境搭建

一、 概述 本文将会介绍 SemiDrive E3 系列 MCU 的MCAL 开发环境搭建&#xff0c;包括如何获取及安装 EB 和 MCAL&#xff0c;E3 Gateway 开发板介绍&#xff0c;MCAL 工程的编译、下载等。 二、 EB 和 MCAL 的获取及安装 2.1 软件获取 EB Tresos 是用于进行 MCAL 配置…

Android Split APK介绍

文章目录 Split APKSplit APK 详细介绍概念Android App Bundle&#xff08;AAB&#xff09;Split APK 的优势动态分发减小安装包大小模块化和渠道分发 Split APK 的类型基于屏幕密度### 基于 CPU 架构基于语言 实现 Split APK Split APK Split APK 是 Android 中一种应用程序安…

【测试运维】web自动化全知识点笔记第1篇:什么是Web自动化测试(已分享,附代码)

本系列文章md笔记&#xff08;已分享&#xff09;主要讨论Web自动化测试相关知识。了解什么是自动化&#xff0c;理解什么是自动化测试以及为什么要使用自动化测试。具体包含&#xff1a;WebDriver的基本操作&#xff0c;WebDriver的鼠标、键盘操作&#xff0c;下拉选择框、警告…

2024.2.4日总结(小程序开发1)

小程序开发和普通网页开发的区别 运行环境不同 网页运行在浏览器环境中&#xff0c;小程序运行在微信环境中 API不同 由于运行的环境不同&#xff0c;所以小程序中无法调用DCM和BOM的API&#xff0c;但是可以调用微信环境提供的各种API&#xff0c;如&#xff1a;地理定位&…

Python 数据分析(PYDA)第三版(一)

原文&#xff1a;wesmckinney.com/book/ 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 关于开放版本 第 3 版的《Python 数据分析》现在作为“开放获取”HTML 版本在此网站wesmckinney.com/book上提供&#xff0c;除了通常的印刷和电子书格式。该版本最初于 2022 年…

微服务基础(持续更新中)

安装SSH以及虚拟机&#xff0c;Centos具体步骤见 https://b11et3un53m.feishu.cn/wiki/FJAnwOhpIihMkLkOKQocdWZ7nUc

vulhub中Adminer ElasticSearch 和 ClickHouse 错误页面SSRF漏洞复现(CVE-2021-21311)

Adminer是一个PHP编写的开源数据库管理工具&#xff0c;支持MySQL、MariaDB、PostgreSQL、SQLite、MS SQL、Oracle、Elasticsearch、MongoDB等数据库。 在其4.0.0到4.7.9版本之间&#xff0c;连接 ElasticSearch 和 ClickHouse 数据库时存在一处服务端请求伪造漏洞&#xff08…

202416读书笔记|《总有人会拥抱满身带刺的你》——今天我请客,想请你快乐

202416读书笔记|《总有人会拥抱满身带刺的你》——今天我请客&#xff0c;想请你快乐 这是一篇暖萌轻松的绘本推荐记录书评&#xff0c;《总有人会拥抱满身带刺的你》纳米著&#xff0c;《今天我请客&#xff0c;想请你快乐》燕七著&#xff0c;都还不错&#xff0c;截取摘录了…

从搜索引擎到答案引擎:LLM驱动的变革

在过去的几周里&#xff0c;我一直在思考和起草这篇文章&#xff0c;认为谷歌搜索正处于被颠覆的边缘&#xff0c;它实际上可能会影响 SEO 作为业务牵引渠道的可行性。 考虑到谷歌二十多年来的完全统治地位&#xff0c;以及任何竞争对手都完全无力削弱它&#xff0c;坦率地说&…

解析 JavaScript 异步编程:从回调地狱到 Promise 和 Async/Await

在现代的JavaScript开发中&#xff0c;处理异步任务变得愈发重要&#xff0c;因为它们允许我们在等待I/O、网络请求或定时器等事件时继续执行其他任务&#xff0c;以提高程序的性能和响应能力。本文将介绍JavaScript中异步编程的演变过程&#xff0c;从最初的回调地狱到后来的P…

【数据结构与算法】(9)基础数据结构 之 阻塞队列的单锁实现、双锁实现详细代码示例讲解

目录 2.8 阻塞队列1) 单锁实现2) 双锁实现 2.8 阻塞队列 之前的队列在很多场景下都不能很好地工作&#xff0c;例如 大部分场景要求分离向队列放入&#xff08;生产者&#xff09;、从队列拿出&#xff08;消费者&#xff09;两个角色、它们得由不同的线程来担当&#xff0c;…

使用绿联私有云Docker搭建自动化实时网页监控工具,实现降价提醒/RSS监控等

使用绿联私有云Docker搭建自动化实时网页监控工具&#xff0c;实现降价提醒/RSS监控等 哈喽小伙伴们好&#xff0c;我是Stark-C~ 之前老是有小伙伴们在评论区说我分享的Docker容器都是通过Docker run命令部署的&#xff0c;能不能照顾下像绿联私有云这种新势力NAS的新手用户&…

C# CAD界面-自定义工具栏(三)

运行环境 vs2022 c# cad2016 调试成功 一、引用 二、开发代码进行详细的说明 初始化与获取AutoCAD核心对象&#xff1a; Database db HostApplicationServices.WorkingDatabase;&#xff1a;这行代码获取当前工作中的AutoCAD数据库对象。在AutoCAD中&#xff0c;所有图形数…

【Git】01 Git介绍与安装

文章目录 一、版本控制系统二、Git三、Windows安装Git3.1 下载Git3.2 安装3.3 检查 四、Linux安装Git4.1 YUM安装4.2 源码安装 五、配置Git5.1 配置用户名和邮箱5.2 配置级别5.3 查看配置 六、总结 一、版本控制系统 版本控制系统&#xff0c;Version Control System&#xff…

【消息队列】kafka整理

kafka整理 整理kafka基本知识供回顾。

基于NSGA-II的深度迁移学习

深度迁移学习 迁移学习是一种机器学习技术&#xff0c;它允许一个预训练的模型被用作起点&#xff0c;在此基础上进行微调以适应新的任务或数据。其核心思想是利用从一个任务中学到的知识来帮助解决另一个相关的任务&#xff0c;即使这两个任务的数据分布不完全相同。这种方法…

vulnhub靶场之Thales

一.环境搭建 1.靶场描述 Description : Open your eyes and change your perspective includes 2 flags:user.txt and root.txt. Telegram: machineboy141 (for any hint) This works better with VIrtualBox rathe than VMware 2.靶场地址 https://www.vulnhub.com/entry/t…