Linux实现生产者消费者模型
目录
概念及优势
代码实现
概念及优势
生产者消费者模型是一种用于线程同步的模型,在这个模型中有两种角色,生产者生产数据,消费者消费数据。有三种关系,生产者与生产者,消费者与消费者,生产者与消费者。还有一个交易场所。
超市就是生活中最常见的生产者消费者模型,工厂生产商品,超市充当缓冲区,消费者去超市消费同时取走超市中的商品。
超市作为缓冲区,起到了很重要的作用,试想如果没有超市,那消费者想购物只能去找工厂,还要等待工厂将商品生产出来,同时工厂也不能持续生产商品,因为没有足够的空间存放,而超市作为缓冲区解决了这些问题,消费者不用去工厂阻塞等待商品生产,工厂也可以一直生产,只要超市还能放得下。
从上面的例子可以看出生产者消费者模型的优点,将生产者和消费者解耦,支持并发,支持忙闲不均。
再来讨论一下这三者间的关系
消费者与消费者不能同时向交易场所写数据,生产者与生产者也不能同时向交易场所拿数据,这两者都是互斥且竞争的关系。而生产者不能与消费者同时拿或写数据,这两者属于互斥且同步的关系。
交易场所的问题,交易场所为空时消费者不能消费,交易场所满时生产者不能生产。
代码实现
基于阻塞队列来实现生产者消费者模型,阻塞队列与普通队列的区别在于,阻塞队列在队列为空是pop操作会阻塞,队列为满时,push操作会阻塞。
//block_queue.hpp
#include <queue>
#include <pthread.h>namespace my
{template<class T>class block_queue{public:block_queue(size_t max_size = 1000):_max_size(max_size){pthread_mutex_init(&_mutex, nullptr);pthread_cond_init(&_consumer_cond, nullptr);pthread_cond_init(&_producer_cond, nullptr);} bool empty() const{return _b_queue.empty();}bool full() const{return _b_queue.size() == _max_size;}//生产者void push(const T& data){pthread_mutex_lock(&_mutex); //加锁//循环判断以防止虚假唤醒//如果用if判断,试想这种场景//线程a在等待,然后被唤醒了,既然被唤醒说明此时应该是不为满//但是被唤醒后还需要竞争锁(因为等待会释放锁),只有线程a再次持有锁//才会醒来执行后面的代码//但是线程a有可能并没有立马拿到锁,被另一个生产者线程b拿到锁//并且b此时判断也是不为满//那么b会向后执行,会向队列里push数据//这就有问题了,在这之后线程a拿到了锁,向后执行,但现在已经是满队列了while(full()){//队列满了,生产者等待//等待必须解锁,否则其他线程都拿不到锁//条件变量等待的条件一定属于临界资源,//所以pthread_cond_wait一定属于临界区代码//所以pthread_cond_wait这个函数在内部一定会解锁来防止死锁//被唤醒后会竞争锁pthread_cond_wait(&_producer_cond, &_mutex); }_b_queue.push(data); //入队std::cout << "生产数据" << data << std::endl;pthread_mutex_unlock(&_mutex); //解锁pthread_cond_signal(&_consumer_cond); //唤醒消费者std::cout << "唤醒消费者" << std::endl;}const T& pop(){pthread_mutex_lock(&_mutex); //加锁//循环判断以防止虚假唤醒while(empty()){pthread_cond_wait(&_consumer_cond, &_mutex); }T& ret = _b_queue.front();std::cout << "消费数据" << ret << std::endl;_b_queue.pop(); //出队 pthread_mutex_unlock(&_mutex); //解锁pthread_cond_signal(&_producer_cond); //唤醒生产者std::cout << "唤醒生产者" << std::endl;return ret;}~block_queue(){pthread_mutex_destroy(&_mutex);pthread_cond_destroy(&_consumer_cond);pthread_cond_destroy(&_producer_cond);} size_t size() const{return _b_queue.size();}private:std::queue<T> _b_queue; //底层容器size_t _max_size; //队列最大容量pthread_mutex_t _mutex; //给队列加锁pthread_cond_t _consumer_cond; //消费者条件变量pthread_cond_t _producer_cond; //生产者条件变量};}
main函数
#include <iostream>
#include <memory>
#include <unistd.h>
#include "block_queue.hpp"using data = int;
void* producer(void* _bq)
{my::block_queue<data>& bq = *(my::block_queue<data>*)_bq;data val = 0;while (true){//使得生产者总是慢于消费者,这样队列一直都只会有一个元素//sleep(2);bq.push(val);val++;}
}void* consumer(void* _bq)
{my::block_queue<data>& bq = *(my::block_queue<data>*)_bq;data val = 0;while (true){val = bq.pop();}
}void test()
{pthread_t tid_consumer1 = 0, tid_producer1 = 0;pthread_t tid_consumer2 = 1, tid_producer2 = 0;pthread_t tid_consumer3 = 2, tid_producer3 = 0;std::shared_ptr<my::block_queue<int>> bq(std::make_shared<my::block_queue<int>>(5));pthread_create(&tid_producer1, nullptr, producer, &(*bq));pthread_create(&tid_producer2, nullptr, producer, &(*bq));pthread_create(&tid_producer3, nullptr, producer, &(*bq));pthread_create(&tid_consumer1, nullptr, consumer, &(*bq));pthread_create(&tid_consumer2, nullptr, consumer, &(*bq));pthread_create(&tid_consumer3, nullptr, consumer, &(*bq));pthread_join(tid_producer1, nullptr);pthread_join(tid_producer2, nullptr);pthread_join(tid_producer3, nullptr);pthread_join(tid_consumer1, nullptr);pthread_join(tid_consumer2, nullptr);pthread_join(tid_consumer3, nullptr);}int main()
{test();return 0;
}
相关文章:
Linux实现生产者消费者模型
目录 概念及优势 代码实现 概念及优势 生产者消费者模型是一种用于线程同步的模型,在这个模型中有两种角色,生产者生产数据,消费者消费数据。有三种关系,生产者与生产者,消费者与消费者,生产者与消费者。…...
AI驱动下的智能异常处置:海量多元异构数据的挑战与应对
摘要 在QCon北京会议上,AI驱动的智能异常处置成为焦点。会议深入探讨了平台复杂性及处理海量多元异构数据时所面临的挑战,特别是异常识别与根本原因定位的难题。这些挑战要求技术从业者不断优化算法,以提升数据处理效率和准确性。 关键词 …...
Axure设计之中继器表格——拖动列调整位置教程(中继器)
一、原理介绍 实现表格列的拖动排序,主要依赖Axure的动态面板和中继器两大核心功能: 动态面板交互控制 将表格的列标题封装在动态面板中,通过拖拽事件(开始、移动、结束)捕捉用户操作 在拖拽过程中实时计算鼠标位置&…...
基于大数据的各品牌手机销量数据可视化分析系统(源码+lw+部署文档+讲解),源码可白嫖!
摘要 时代在飞速进步,每个行业都在努力发展现在先进技术,通过这些先进的技术来提高自己的水平和优势,各品牌手机销量数据可视化分析系统当然不能排除在外。基于大数据的各品牌手机销量数据可视化分析系统是在实际应用和软件工程的开发原理之…...
Open CASCADE学习|基于AIS_PointCloud显示点集
定义与用途 AIS_PointCloud是OpenCASCADE中用于表示和管理点云数据的类,能够高效地绘制大量任意彩色点集。它通过Graphic3d_ArrayOfPoints将点数据传递给OpenGL图形驱动程序,以将设定点绘制为“点精灵”数组,且点数据被打包到顶点缓冲区对象…...
c++随记
内存溢出与内存泄漏的区别 今天老师提出的概念问题,搜索了一下 # 内存泄漏与内存溢出的区别 内存泄漏(Memory Leak)和内存溢出(Memory Overflow/Out of Memory)是两种常见的内存相关问题,但它们的含义和产生原因不同: ## 内存泄漏 (Memor…...
GOC作业
实验室logo 题目描述 绘制烧毁实验室logo,它是由半径120,颜色6号色的空心元构成,中间的图案由线段长度为75,半径为15的实心圆构成,颜色从1号色开始,到6号色,如图所示 代码参考: …...
本地部署仓库管理工具 Gitlab 并实现外部访问
Gitlab是一款自托管的 Git 仓库管理工具,它提供了完整的代码管理功能,包括代码托管、版本控制、代码合并请求、问题追踪、持续集成等。 本文将详细的介绍如何利用 Docker 在本地部署 Gitlab 并结合路由侠实现外网访问本地部署的 Gitlab 。 第一步&am…...
华鲲振宇天工TG225 B1国产服务器试装openEuler22.03 -SP4系统
今天测试了一下在华鲲振宇公司的天工TG225 B1国产服务器上进行openEuler22.03 -SP4操作系统的试装,本文记录整个测试过程。 一、服务器信息 1、服务器型号 Huakun TG225 B1 (D) 2、登录IPMI帐户信息 初始用户名Tech.ON 密码TianGong8000 二、磁盘RAID配置 测试…...
自然语言处理NLP-文本预处理
在自然语言处理(NLP)中,文本预处理是构建高效模型的关键步骤。原始文本通常包含噪声和不一致性,直接影响模型性能。通过预处理,可以提取结构化信息、减少计算复杂度,并提升模型对语义的理解能力。 一、为什…...
linux常用指令(9)
加油同志们,我们离胜利不远了,再有两天我们就可以了解完linux的一些基本常用指令了,到时我们便可以进入一些shell脚本语法了,那么话不多说,来看. 1.more指令 功能描述:more指令是一个基于vi编辑器的文本过滤器,它以全屏幕的方式按页显示文本文件的内容. 基本语法…...
【windows搭建lvgl模拟环境之VSCode】
搭建vscodelvgl8.3所有资料,0积分 通过在windows搭建LVGL模拟环境方便UI界面开发和调试,后续只需将相关的代码移植到项目中即可,方便调试,PC上支持下列模拟器: 本文说明两种方法搭建模拟器环境,分别采用&am…...
【BFS染色问题】P1162填涂颜色例题+核心逻辑
文章目录 【算法思路】【代码示例】 BFS处理染色问题的核心逻辑 【算法思路】 要判断一个数字 0 是否在闭合圈内,可以换个角度思考。不在闭合圈内的 0 是可以从方阵的边界出发,通过上下左右移动,只经过其他 0 到达的。 思路①.我们可以从方…...
【多学科稳定EI会议大合集】计算机应用、通信信号、电气能源工程、社科经管教育、光学光电、遥感测绘、生物医学等多学科征稿!
在当今科技高速发展的时代,多学科领域的学术交流与融合显得尤为重要。以下是稳定EI会议合集,涵盖计算机、信息通信、电气能源、社科经管教育、光学遥感、生物医学等多个学科领域。 会议皆已通过国际知名出版社出版审核,EI检索稳定࿰…...
ElasticSearch -- 部署完整步骤
前期准备 创建用户: sudo useradd hadoop sudo passwd hadoop# 密码 xxx系统层面,禁用内存交换 sudo swapoff -a修改 sudo vi /etc/security/limits.conf hadoop hard memlock unlimited hadoop soft memlock unlimited hadoop soft nofile 65536 had…...
医学交互作用分析步骤和目的(R语言)
医学交互作用分析的目的和用途(R语言) 医学交互作用分析一直是医学数据分析的组成部分,总结最近的一些认识。 目的: 在独立危险因素鉴定的研究中,(独立危险因素的)交互作用可以作为独立危险因…...
创新前沿 | 接管主机即刻增量CDP备份,高效保障接管期间业务安全!
科力锐创新前沿系列 接管主机增量CDP备份 高效保障接管业务安全 当核心系统遭遇系统故障或误操作导致数据逻辑损毁等,往往需要将生产业务主机接管起来,继续对外提供服务,保障业务连续性。 然而,你的接管主机真的安全吗?一旦接…...
《基于python游戏设计与实现》开题报告
个人主页:@大数据蟒行探索者 一、研究背景、目的及意义 (一)研究背景 游戏的普及与成功:随着智能手机的普及和网络技术的发展,手机游戏产业逐渐成熟,成为娱乐文化产业的重要组成部分。《开心消消乐》作为一款休闲类游戏,自上线以来凭借其简单易上手的玩法和丰富的…...
Netty源码—7.ByteBuf原理三
大纲 9.Netty的内存规格 10.缓存数据结构 11.命中缓存的分配流程 12.Netty里有关内存分配的重要概念 13.Page级别的内存分配 14.SubPage级别的内存分配 15.ByteBuf的回收 9.Netty的内存规格 (1)4种内存规格 (2)内存申请单位 (1)4种内存规格 一.tiny:表示从…...
(免费开源)图片去水印以及照片擦除功能,你会选择使用吗?
图片去水印以及相关人物擦除是一个非常小众的需求,就是将原本图片上的文字或者logo去除让变成一个干净的图片,但市面上很多都是付费的,今天就介绍一下这款免费工具。 工具演示效果 工具介绍 名称:lama-projct 利用AI模型训练LaM…...
2025-03-26 学习记录--C/C++-PTA 6-2 顺序表操作集
合抱之木,生于毫末;九层之台,起于累土;千里之行,始于足下。💪🏻 一、题目描述 ⭐️ 6-2 顺序表操作集 本题要求实现顺序表的操作集。 函数接口定义: 👇🏻 …...
SQL-木马植入、报错注入及其他
一、读写权限确认 show global variables like %secure%; 查看mysql全局变量的配置,当输入以上命令时,结果 secure_file_priv 空的时候,任意读写 secure_file_priv 某个路径的时候,只能在规定的那个路径下读写 secure_file_pri…...
用C#实现UDP服务器
对UDP服务器的要求 如同TCP通信一样让UDP服务端可以服务多个客户端 需要具备的条件: 1.区分消息类型(不需要处理分包、黏包) 2.能够接收多个客户端的消息 3.能够主动给自己发过消息的客户端发消息(记录客户端信息)…...
React 组件之间的通信
React 组件通信 对于 React 组件之间的通信,我们首先了解一下 React 组件通信的设计理念。 单向数据流(Unidirectional Data Flow) 数据流向明确: 在 React 中,数据总是从父组件流向子组件(通过 Props 传…...
[C++面试] span<char>和string_view的差别
1、概念 std::string_view是领域特定设计(字符串)。C17引入,仅用于处理以空字符(\0)结尾的字符序列;仅支持字符类型(如 char、wchar_t、std::string),用于高效访问字符串…...
在 VMware Workstation 17 中安装的 Ubuntu 虚拟机无法使用桥接模式
在 VMware Workstation 17 中安装的 Ubuntu 虚拟机无法使用桥接模式时,通常是由于 网络配置错误、桥接适配器选择不当或主机网络环境限制 导致。以下是详细的排查和解决方法:我采用第一步就解决了问题 1. 检查 VMware 桥接模式配置 步骤 1:…...
谐波和三相不平衡度
谐波(Harmonics) 谐波是指在电力系统中,由于非线性负载的作用,导致电流或电压波形偏离理想正弦波形的现象。具体来说: 定义: 在理想情况下,交流电的电压和电流波形是正弦波。然而,由于电力系统中存在非线性负载(如变频器、整流器、开关电源等),这些负载会使得电流或…...
深克隆和浅克隆(建造者模式,内含简版)
让我们来看一个例子: 设计一个客户类Customer,其中客户地址存储在地址类Address中,用浅克隆和深克隆分别实现Customer对象的复制并比较这两种克隆方式的异同。 代码实现 Customer类和Address类都是实现的Java 内置的 java.lang.Cloneable …...
印刷电路板 (PCB) 的影响何时重要?在模拟环境中导航
我和我的同事们经常被问到关于 PCB 效应的相同问题,例如: 仿真何时需要 PCB 效果? 为什么时域仿真需要 PCB 效应? 当 PCB 效应必须包含在仿真中时,频率是否重要? 设计人员应该在多大程度上关注 VRM 模型中包…...
循环队列 bug
1. 题目描述 spfa判断负环 LC 设计循环队列 2. 普通单队列 int q[N]; int hh 0, tt -1; while(hh < tt) // empty {int t q[ hh ]; // push/* do something */q[ tt ] j; // pop }3. 错误的循环队列 int q[N]; int hh 0, tt -1; while(hh ! (tt 1) % N) // 非空 …...
