【lesson56】生产者消费者模型
文章目录
- 学习生产者消费者模型过程中要回答的两个问题
- 生产者消费者模型的概念
- 基于阻塞队列的生产者消费者模型
- 编码实现
- Common.h
- LockGuard.hpp
- Condtion.hpp
- BlockQueue.hpp
- Task.hpp
- ConProd.cc
学习生产者消费者模型过程中要回答的两个问题
1.条件变量是在条件满足的时候,会唤醒指定的线程---->我们怎么知道条件是否满足呢?
2.mutex的意义
生产者消费者模型的概念
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产
者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
生产者消费者模型:

生产者消费者模型优点
解耦
支持并发
支持忙闲不均
上面的优点全都是因为有一个仓库的存在。
生产者消费者模型类比:

消费者去超市买商品。
厂家往超市放商品
而这就是生产者消费者模型它的核心意义是提高了效率,并且通过超市让消费者和厂家进行了解耦合的关系,不用让消费者和厂家进行沟通。
超市本质就是一个商品缓冲区。
生产者消费者模型有:
2种角色:生产者和消费者
1种交易场所:超市
3中关系:
生产者和生产者-----竞争且互斥
消费者和消费者----竞争且互斥
生产者和消费者----互斥且同步
消费者和生产者由线程承担----给线程进行角色化
超市:某种数据结构—表示缓冲区
商品:数据
生产者生产的数据是从哪里来的?
消费者如何使用发送过来的数据?
而在现实生活中生产数据和发送数据的过程都需要花时间。
1.条件变量是在条件满足的时候,会唤醒指定的线程---->我们怎么知道条件是否满足呢?消费者和生产者各自知道。
超市没有商品了,消费者知道。(因为消费者去超市买不到商品)
超市商品满了,生产者知道(因为生产者刚想超市放了一堆商品)
2.mutex的意义
保护临界资源
基于阻塞队列的生产者消费者模型
BlockingQueue 在多线程编程中阻塞队列(Blocking Queue)是一种常用于实现生产者和消费者模型的数据结构。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素;当队列满时,往队列里存放元素的操作也会被阻塞,直到有元素被从队列中取出(以上的操作都是基于不同的线程来说的,线程在对阻塞队列进程操作时会被阻塞)
编码实现
Common.h
#pragma once
#include <iostream>
#include <pthread.h>
#include <queue>
#include <unistd.h>
#include <ctime>
#include <functional>#define gDefaultCap 5//阻塞队列默认的数据个数
#define CTNUM 1//消费者线程个数
#define PTNUM 1//生产者线程个数
LockGuard.hpp
//自己封装的锁,定义后会自动初始化和销毁
#pragma once
#include "Common.h"class Mutex
{
public:Mutex(){pthread_mutex_init(&_mtx,nullptr);}pthread_mutex_t& GetMutex(){return _mtx;}~Mutex(){pthread_mutex_destroy(&_mtx);}
private:pthread_mutex_t _mtx;
};//RAII风格,会自动加锁和解锁
class LockGuard
{
public:LockGuard(Mutex* mtx):_mtx(mtx){pthread_mutex_lock(&_mtx->GetMutex());//std::cout << "lock" << std::endl;}~LockGuard(){pthread_mutex_unlock(&_mtx->GetMutex());//std::cout << "unlock" << std::endl;}
private:Mutex* _mtx;
};
Condtion.hpp
#include "Common.h"
//自己封装的条件变量,定义后会自动初始化和销毁
class Condtion
{
public:Condtion(){pthread_cond_init(&_cond,nullptr);}pthread_cond_t& GetCond(){return _cond;}~Condtion(){pthread_cond_destroy(&_cond);}
private:pthread_cond_t _cond;
};
BlockQueue.hpp
#pragma once
#include "Common.h"
#include "LockGuard.hpp"
#include "Condtion.hpp"template<class T>
class BlockQueue
{
private:bool Empty(){return bq.size() == 0;}bool Full(){return bq.size() == _capacity;}
public:BlockQueue(int capacity = gDefaultCap):_capacity(capacity){}void Push(T& in){//RAII风格加锁,会自动解锁LockGuard lockgrard(&_mtx);//条件不满足就一直等待while(Full()){pthread_cond_wait(&_FullCond.GetCond(),&_mtx.GetMutex());}bq.push(in);//唤醒消费者线程pthread_cond_signal(&_EmptyCond.GetCond());}void Pop(T* out){//RAII风格加锁,会自动解锁LockGuard lockgrard(&_mtx);//条件不满足就一直等待while(Empty()){pthread_cond_wait(&_EmptyCond.GetCond(),&_mtx.GetMutex());}*out = bq.front();bq.pop();//唤醒生产者线程pthread_cond_signal(&_FullCond.GetCond());}~BlockQueue(){}
private:std::queue<T> bq;//阻塞队列int _capacity;//阻塞队列的最大容量Mutex _mtx;//自己封装的锁,会自动初始化和销毁Condtion _EmptyCond;//自己封装的条件变量,会自动初始化和销毁Condtion _FullCond;//自己封装的条件变量,会自动初始化和销毁
};
Task.hpp
#pragma once
#include "Common.h"typedef std::function<int(int, int)> func_t;class Task
{
public:Task(){}Task(int x, int y, func_t func): _x(x),_y(y),_func(func){}//仿函数int operator()(){return _func(_x, _y);}public:int _x;int _y;func_t _func;
};
ConProd.cc
#include "Common.h"
#include "BlockQueue.hpp"
#include "Task.hpp"int myAdd(int x,int y)
{return x+y;
}void* ConsumerRoutine(void* args)
{BlockQueue<Task>* bq = (BlockQueue<Task>*)args;Task t;while(true){//获取一个任务bq->Pop(&t);std::cout << "[" << pthread_self() << "] 获取一个任务:" << t._x << " + " << t._y << " = " << t() << std::endl;sleep(1);}
}
void* ProducterRoutine(void* args)
{BlockQueue<Task>* bq = (BlockQueue<Task>*)args;while(true){//制作一个任务int x = rand() % 100 + 1;int y = rand()%30 + 1;Task t(x,y,myAdd);std::cout << "[" << pthread_self() << "] 制作一个任务:" << x << " + " << y << " =?" << std::endl;bq->Push(t);sleep(1);}
}
int main()
{srand((unsigned int)time(nullptr) ^ getpid() ^ 0X3333);//定义消费者线程和生成者线程的id数组pthread_t Consumer[CTNUM];pthread_t Producter[PTNUM];//创建阻塞队列BlockQueue<Task>* bqueue = new BlockQueue<Task>;//创建消费者线程for(int i = 0; i < CTNUM; i++){pthread_create(Consumer + i,nullptr,ConsumerRoutine,(void*)bqueue);}//创建生产者线程for(int i = 0; i < PTNUM; i++){pthread_create(Producter + i,nullptr,ProducterRoutine,(void*)bqueue);}//等待消费者线程for(int i = 0; i < CTNUM; i++){pthread_join(Consumer[i],nullptr);}//等待生产者线程for(int i = 0; i < CTNUM; i++){pthread_join(Producter[i],nullptr);}return 0;
}
相关文章:
【lesson56】生产者消费者模型
文章目录 学习生产者消费者模型过程中要回答的两个问题生产者消费者模型的概念基于阻塞队列的生产者消费者模型编码实现Common.hLockGuard.hppCondtion.hppBlockQueue.hppTask.hppConProd.cc 学习生产者消费者模型过程中要回答的两个问题 1.条件变量是在条件满足的时候&#x…...
MySQL5.7升级到MySQL8.0的最佳实践分享
一、前言 事出必有因,在这个月的某个项目中,我们面临了一项重要任务,即每年一次的等保测评整改。这次测评的重点是Mysql的一些高危漏洞,客户要求我们无论如何必须解决这些漏洞。尽管我们感到无奈,但为了满足客户的要求…...
Rust 数据结构与算法:5栈:用栈实现前缀、中缀、后缀表达式
3、前缀、中缀和后缀表达式 计算机是从左到右处理数据的,类似(A (B * C))这样的完全括号表达式,计算机如何跳到内部括号计算乘法,然后跳到外部括号计算加法呢? 一种直观的方法是将运算符移到操作数外,分离运算符和操…...
作业day6
数据库 sqlite3 sq.db 如果sq.db存在则直接打开sq.db数据库,如果不存在则先创建再打开; 系统命令 需要以 . 开头,不需要以 ; 结尾 .quit 退出数据库 .exit 退出数据库 .help 显示帮助信息,获取所有系统命令; .table 查看当前数据…...
前方预警!2024年七大网络安全威胁
新颖创新技术的兴起和迅速采用已极大地改变了各行各业的全球网络安全和合规格局,比如生成式人工智能、无代码应用程序、自动化和物联网等新技术。 网络犯罪分子正转而采用新的技术、工具和软件来发动攻击,并造成更大的破坏。因此,《2023年网…...
绿色化 数据库 MongoDB 和 mysql 安装
绿色化 数据库 MongoDB 和 mysql 安装 【1.1】 前言 为什么要绿色化 安装呢?因为系统老升级,老重装!!也方便了解下数据库配置和库在那 绿色软件喜欢一般放在 D盘tools目录里 D:\tools\ 数据库 MongoDB D:\tools\MongoDB 数…...
npm install 一直卡着不动如何解决
目录 方式一:方式二: 方式一: npm cache clean --force npm config set registry https://registry.npmmirror.com npm install下面是简单的解释: 🍀1、强制清理 npm 缓存 npm cache clean --force🍀2、设…...
电路设计(15)——篮球赛24秒违例倒计时报警器的proteus仿真
1.设计要求 设计、制作一个篮球赛24秒违例倒计时报警器。要求: (1)具有倒计时功能。可完整实现从“24”秒开始依序倒计时并显示倒计时过程,显示时间间隔为1秒。 (2)具有消隐功能。当“24”秒倒计时…...
golang 集成sentry:http.Client
http.Client 是 Go 标准库 HTTP 客户端实现, sentry-go也没有这个组件,所以需要自己实现。 我们只需要对 http.Transport 进行包装即可, 完整代码如下 package mainimport ("bytes""fmt""io""log"&…...
设计链表(不难,代码稍微多一点)
设计链表 在链表类中实现这些功能: get(index):获取链表中第 index 个节点的值。如果索引无效,则返回-1。addAtHead(val):在链表的第一个元素之前添加一个值为 val 的节点。插入后,新节点将成为链表的第一个节点。ad…...
[GXYCTF2019]禁止套娃
进来发现只有这句话,习惯性访问一下flag.php,发现不是404,那就证明flag就在这了,接下来要想办法拿到flag.php的源码。 这道题是.git文件泄露网页源码,githack拿到index.php源码 这里观察到多次判断,首先要…...
ubuntu下如何查看显卡及显卡驱动
ubuntu下如何查看显卡及显卡驱动 使用nvidia-smi 工具查看 查看显卡型号nvida-smi -L $ nvidia-smi -L GPU 0: NVIDIA GeForce RTX 3050 4GB Laptop GPU (UUID: GPU-4cf7b7cb-f103-bf56-2d59-304f8996e28c)当然直接使用nvida-smi 命令可以查看更多信息 $ nvidia-smi Mon Fe…...
【图论经典题目讲解】CF786B - Legacy 一道线段树优化建图的经典题目
C F 786 B − L e g a c y \mathrm{CF786B - Legacy} CF786B−Legacy D e s c r i p t i o n \mathrm{Description} Description 给定 1 1 1 张 n n n 个点的有向图,初始没有边,接下来有 q q q 次操作,形式如下: 1 u v w 表示…...
【AIGC】Stable Diffusion的采样器入门
在 Stable Diffusion 中,采样器(Sampler)是指用于生成图像的一种技术或方法,它决定了模型如何从潜在空间中抽样并生成图像。采样器在生成图像的过程中起着重要作用,影响着生成图像的多样性、质量和创造性。以下是对 St…...
【Python】通过conda安装Python的IDE
背景 系统:win11 软件:anaconda Navigator 问题现象:①使用Navigator安装jupyter notebook以及Spyder IDE 一直转圈。②然后进入anaconda prompt执行conda install jupyter notebook一直卡在Solving environment/-\。 类似问题: …...
基于HTML5实现动态烟花秀效果(含音效和文字)实战
目录 前言 一、烟花秀效果功能分解 1、功能分解 2、界面分解 二、HTML功能实现 1、html界面设计 2、背景音乐和燃放触发 3、燃放控制 4、对联展示 5、脚本引用即文本展示 三、脚本调用及实现 1、烟花燃放 2、燃放响应 3、烟花canvas创建 4、燃放声音控制 5、实际…...
「数据结构」栈和队列
栈 栈的基本概念 定义 栈是只允许在一端进行插入或删除操作的线性表栈顶:线性表允许进行插入删除的那一端栈底:固定的,不允许进行插入和删除的另一端空栈:不含任何元素特点:后进先出(LIFO) 基…...
【机器学习笔记】5 机器学习实践
数据集划分 子集划分 训练集(Training Set):帮助我们训练模型,简单的说就是通过训练集的数据让我们确定拟合曲线的参数。 验证集(Validation Set):也叫做开发集( Dev Set …...
C++ //练习 7.5 在你的Person类中提供一些操作使其能够返回姓名和住址。这些函数是否应该是const的呢?解释原因。
C Primer(第5版) 练习 7.5 练习 7.5 在你的Person类中提供一些操作使其能够返回姓名和住址。这些函数是否应该是const的呢?解释原因。 环境:Linux Ubuntu(云服务器) 工具:vim 解释 姓名大概…...
python系统学习Day2
section3 python Foudamentals part one:data types and variables 数据类型:整数、浮点数、字符串、布尔值、空值 #整型,没有大小限制 >>>9 / 3 #3.0 >>>10 // 3 #3 地板除 >>>10 % 3 #1 取余#浮点型ÿ…...
深入浅出Asp.Net Core MVC应用开发系列-AspNetCore中的日志记录
ASP.NET Core 是一个跨平台的开源框架,用于在 Windows、macOS 或 Linux 上生成基于云的新式 Web 应用。 ASP.NET Core 中的日志记录 .NET 通过 ILogger API 支持高性能结构化日志记录,以帮助监视应用程序行为和诊断问题。 可以通过配置不同的记录提供程…...
AI Agent与Agentic AI:原理、应用、挑战与未来展望
文章目录 一、引言二、AI Agent与Agentic AI的兴起2.1 技术契机与生态成熟2.2 Agent的定义与特征2.3 Agent的发展历程 三、AI Agent的核心技术栈解密3.1 感知模块代码示例:使用Python和OpenCV进行图像识别 3.2 认知与决策模块代码示例:使用OpenAI GPT-3进…...
蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据
微软PowerBI考试 PL300-在 Power BI 中清理、转换和加载数据 Power Query 具有大量专门帮助您清理和准备数据以供分析的功能。 您将了解如何简化复杂模型、更改数据类型、重命名对象和透视数据。 您还将了解如何分析列,以便知晓哪些列包含有价值的数据,…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
免费数学几何作图web平台
光锐软件免费数学工具,maths,数学制图,数学作图,几何作图,几何,AR开发,AR教育,增强现实,软件公司,XR,MR,VR,虚拟仿真,虚拟现实,混合现实,教育科技产品,职业模拟培训,高保真VR场景,结构互动课件,元宇宙http://xaglare.c…...
代码规范和架构【立芯理论一】(2025.06.08)
1、代码规范的目标 代码简洁精炼、美观,可持续性好高效率高复用,可移植性好高内聚,低耦合没有冗余规范性,代码有规可循,可以看出自己当时的思考过程特殊排版,特殊语法,特殊指令,必须…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
