生产者和消费者模型 | 阻塞队列 | 信号量 | 环形队列

文章目录

        • 1.生产者和消费者模型
        • 2.生产者和消费者模型优点
        • 3.阻塞队列
        • 4.POSIX信号量
        • 5.基于环形队列的生产消费模型

本文完整的代码放在了这: Gitee链接

1.生产者和消费者模型

生产者和消费者模型,概括起来其实是一个321原则:3是:三种关系,2是两种角色,1是1个交易场所。

三种关系有:生产者和生产者、消费者和消费者、生产者和消费者。

  1. 其中生产者vs生产者之间是:互斥关系。就好比如一家超市,两种品牌的供应商之间是竞争的关系,假设同一时间只有一家供应商能向超市供货,超市就是临界资源。所以用互斥保障安全。
  2. 消费者vs消费者也是互斥关系。如果是在沙漠上,你和你的舍友都非常渴,如果只有一瓶水,那么不得抢起来啊!所以消费者和消费者之间也要保证互斥关系。
  3. 而生产者和消费者则是:互斥和同步的关系。为什么要是互斥呢? 假设超市有一个冰柜,生产者需要往冰柜上放上雪糕,而正好消费者要拿生产者要放到冰柜的拿个雪糕。那么消费者有没有那个雪糕呢?这取决于雪糕还是没放,这是不确定的,在生产者消费者模型等中,要是确定性的。雪糕要么放到冰柜,要么不放到冰柜!不能是将放未放!所以互斥是保障其安全性
    为什么要同步呢? 供应商刚往超市供完货,然后一直打电话问超市要不要供货,电话信道一直被供应商占有,消费者想打电话没东西都没有机会。所以要保障生产者和消费者之间有一定的顺序性,供应商刚刚把货供满就等等,等到消费得差不多了,再来供货。

角色是生成者和消费者。

一个交易场所,上面举例中,我们把超市到当成了交易的场所。在计算机中,这个交易场所就是一块特定的内存空间!

2.生产者和消费者模型优点
  • 多线程站在调度的角度是提高CPU的并发度,而站在编码角度,天然的解耦!生产者消费者模型起到解耦的作用
  • 支持忙闲不均,也就是说,可以支持生产者和消费的处理能力的不同
  • 支持并发,生产者和消费者模型是高效的,为什么呢?首先生产者生产数据可以从用户中来或者网络中来,生产数据是要花费时间的;同样的道理消费者消费数据也是需要花费时间的,在生产者生产数据,消费者消费数据,这同一时刻,它们有很大的概率是并发执行的!它的高效并不能只关注放数据和取数据的角度上!
3.阻塞队列

阻塞队列(Blocking Queue)是一种常用于实现生产者和消费者模型的数据结构。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素;当队列满时,往队列里存放元素的操作也会被阻塞,直到有元素被从队列中取出。

在这里插入图片描述

参考代码

#pragma once    
#include <iostream>
#include <queue>
#include <pthread.h>
#include <unistd.h>template <class Type>
class bolck_queue
{
public:bolck_queue(int max_capacity = 5){_max_capacity = max_capacity;pthread_mutex_init(&_lock,nullptr);pthread_cond_init(&_producer_cond,nullptr);pthread_cond_init(&_consumer_cond,nullptr);_hight_water = (2/3) * _max_capacity;_low_water = (1/3) * _max_capacity;}~bolck_queue(){pthread_mutex_destroy(&_lock);pthread_cond_destroy(&_producer_cond);pthread_cond_destroy(&_consumer_cond);}
public:// 生产者,生产操作void push(const Type& input){pthread_mutex_lock(&_lock);/*这里(伪唤醒)if(_queue.size() == _max_capacity){pthread_cond_wait(&_producer_cond,&_lock);}*/while (_queue.size() == _max_capacity){pthread_cond_wait(&_producer_cond,&_lock);}// 符合条件,可以生产_queue.push(input);// 这里生成完毕可以告诉消费者可以消费了if(_queue.size() > _hight_water){pthread_cond_signal(&_consumer_cond);}pthread_mutex_unlock(&_lock);}// 消费者,消费操作Type pop(){pthread_mutex_lock(&_lock);// 同理while防止伪唤醒while(_queue.size() == 0){pthread_cond_wait(&_consumer_cond,&_lock);}// 符合条件,可以消费Type output = _queue.front();_queue.pop();// 这里消费了,可以告诉生产者来生产了!这里可以定制策略if(_queue.size() < _low_water){pthread_cond_signal(&_producer_cond);}pthread_mutex_unlock(&_lock);return output;}
private:    std::queue<Type> _queue;        // 交易场所,缓存(这里把_queue当成一个整体!)int _max_capacity;              // 极值,阻塞队列的最大值pthread_mutex_t _lock;          // 一把锁,为什么? 保证三种关系的互斥关系!pthread_cond_t _producer_cond;  // 生产者条件变量pthread_cond_t _consumer_cond;  // 消费者条件变量int _hight_water;               // 高水位int _low_water;                 // 低水位
};
4.POSIX信号量

POSIX信号量和SystemV信号量作用相同,都是用于同步操作,达到无冲突的访问共享资源目的。 但POSIX可以用于线程间同步。

信号量的本质是计数器! 用来描述资源,当申请信号量时就已经间接的判断临界资源是否就绪,如果申请成功就一定有对应的资源!就好比如,去电影院买票,只有票(信号量)买上了,就一定有对应的位置供你观影使用!同样的线程,成功申请了信号量,那里临界资源一定有线程所能访问的资源。

初始化信号量

int sem_init(sem_t *sem, int pshared, unsigned int value);
参数:pshared:0表示线程间共享,非零表示进程间共享value:信号量初始值

销毁信号量

int sem_destroy(sem_t *sem);

等待信号量

功能:等待信号量,会将信号量的值减1
int sem_wait(sem_t *sem); // P()操作

发布信号量

功能:发布信号量,表示资源使用完毕,可以归还资源了。将信号量值加1int sem_post(sem_t *sem);// V()操作
5.基于环形队列的生产消费模型

在这里插入图片描述

假设两个人,一个人(生产者)往桌子上摆蛋糕,一个人(消费者)往桌子上取蛋糕。

  1. 当为空或者满时,这个下标对应的位置只有一个人能访问,为空只能时生产者访问,放蛋糕,为满只能是消费者能访问,取蛋糕,其他情况两个人都能同时访问
  2. 生产者不能太快,不能给消费者套一个圈
  3. 消费者者不能太快,不能超过生产者

这里假定两个人,是单生产和单消费!也可以是放蛋糕的人有多个,取蛋糕的人也有多个,对应是多生产多消费!

上面可以通过信号量,来处理生产者和消费者的关系! 生产者关注的是空间(space = N),而消费者关注的是数据(data = 0)

在这里插入图片描述

要通过两个锁,保证生产者VS生产者;消费者VS消费者的互斥关系

参考代码

#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>template <class T>
class ring_queue
{
public:ring_queue(int capacity = 5):_ring_queue(capacity),_capacity(capacity),_consumer_step(0),_producter_step(0){sem_init(&_c_data_sem,0,0);sem_init(&_p_space_sem,0,capacity);pthread_mutex_init(&_c_lock,nullptr);pthread_mutex_init(&_p_lock,nullptr);}~ring_queue(){sem_destroy(&_c_data_sem);sem_destroy(&_p_space_sem);pthread_mutex_destroy(&_c_lock);pthread_mutex_destroy(&_p_lock);}
private:void P(sem_t& sem){sem_wait(&sem);}void V(sem_t& sem){sem_post(&sem);}void lock(pthread_mutex_t& lock){pthread_mutex_lock(&lock);}void unlock(pthread_mutex_t& lock){pthread_mutex_unlock(&lock);}public:void push(const T& input){P(_p_space_sem);lock(_p_lock);_ring_queue[_producter_step] = input;_producter_step++;_producter_step %= _capacity;unlock(_p_lock);V(_c_data_sem);}T pop(){/*lock(_c_lock);P(_c_data_sem);为什么不是这样了,加锁放在P操作之前?理由1: P是原子的不需要保护,加锁之间的代码要尽可能少理由2:要让信号量尽可能去,先获取,当锁一旦释放,里面就能竞争锁,而不是持有锁去竞争!就好如:电影院先买票(信号量),然后电影开映直接持有票,进场看电影       */P(_c_data_sem);lock(_c_lock);T output = _ring_queue[_consumer_step];_consumer_step++;_consumer_step %= _capacity;unlock(_c_lock);V(_p_space_sem);return output;}
private:std::vector<T> _ring_queue;     // 缓冲区,将其看成多份临界资源int _capacity;                  // 缓冲区的大小int _consumer_step;             // 消费者下标int _producter_step;            // 生产者下标sem_t _c_data_sem;              // 消费者关注的资源的信号量sem_t _p_space_sem;             // 生产者关注的空间的信号量pthread_mutex_t _c_lock;        // 解决消费者VS消费者之间的:互斥问题pthread_mutex_t _p_lock;        // 解决生产者VS生成者之间的:互斥问题
};

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

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

相关文章

Spring Boot(04):让你的Spring Boot应用“火力全开”,从零开始学习starter

1. 前言 Spring Boot是一款非常流行的Java开发框架&#xff0c;其具有快速开发、自动化配置、内嵌服务器、易于扩展等特点&#xff0c;因此备受开发者欢迎。在日常开发中&#xff0c;我们经常需要在不同的环境中进行测试和部署&#xff0c;此时&#xff0c;如何实现开发、测试、…

电子方案 红外遥控蜘蛛玩具

东莞市酷得智能科技在消费类电子市场深耕多年&#xff0c;依托于市场团队对市场的敏锐度、工程团队的技术积累、结合自身的创新以及和上游原厂深度合作&#xff0c;在2.4G通信、BLE、语音、马达驱动控制等领域&#xff0c;采用方案代理的模式&#xff0c;形成了自己的多条具有市…

k8s-配置与存储-持久化存储-NFS 挂载、StorageClass 存储类 动态创建NFS-PV案例

文章目录 Volumes (依赖本机来实现&#xff09;1.1EmptyDir1.2 HostPath NFS 挂载(依赖远程服务来实现)安装 nfs挂载 NFS 共享目录配置文件 NFS 挂在到容器里去 高级存储 PV与PVC 概念详解PV与PVC 生命周期构建绑定使用回收策略 创建PV与PVC以及关联Pod创建 PersistentVolume&a…

【Python】面向对象(专版提升2)

面向对象 1. 概述1.1面向过程1.2 面向对象 2. 类和对象2.1 语法2.1.1 定义类2.1.2 实例化对象 2.2 实例成员2.2.1 实例变量2.2.2 实例方法2.2.3 跨类调用 3. 三大特征3.1 封装3.1.1 数据角度3.1.2 行为角度3.1.3 案例:信息管理系统3.1.3.1 需求3.1.3.2 分析3.1.3.3 设计 3.2 继…

服务器 安装1Panel服务器运维管理面板

服务器 安装1Panel服务器运维管理面板 SSH链接服务器安装1Panel 出现此提示时输入目标路径&#xff0c;须以“/”开头&#xff0c;默认&#xff1a;/opt&#xff0c;本例&#xff1a;/www。 出现此提示时输入目标端口&#xff0c;须未被使用的端口&#xff0c;默认&#xff1…

【MYSQL管理工具】数据库备份和恢复

&#x1f525;作者主页&#xff1a;小林同学的学习笔录 &#x1f525;mysql专栏&#xff1a;小林同学的专栏 目录 1.MYSQL管理 1.1 系统数据库 1.2 常用工具 1.2.1 mysql 1.2.2 mysqladmin 1.2.3 mysqlbinlog 1.2.4 mysqlshow 1.2.5 mysqldump 1.2.6 mysqlimport/sour…

本地web项目启起来后,无法在浏览器(chrome)看到源码,从而无法打断点;Framework Ignore list

问题描述 本地web项目启起来后&#xff0c;无法在浏览器(chrome)看到源码&#xff0c;从而无法打断点 其他浏览器没看&#xff0c;开发环境一致专注于chrome&#xff08;其余浏览器有测试同事提缺陷了&#xff0c;才会去看&#xff09;&#xff0c;其余浏览器有没有这个问题&…

Docker 镜像推送到docker hub

查看容器 #sudo docker ps -a commit容器为镜像 $ sudo docker commit d7b5e8d56a75 ubuntu_pytorch39_v4 #sha256: ********** 查看镜像信息 $ sudo docker images 登录 docker hub $ sudo docker login --username用户名 registry.cn-beijing.aliyuncs.com #密码 为…

AIGC的崛起:定义未来内容创作的新纪元

&#x1f31f;文章目录 &#x1f31f;AIGC简介&#x1f31f; AIGC的相关技术与特点&#x1f31f;AIGC有哪些应用场景&#xff1f;&#x1f31f;AIGC对其他行业影响&#x1f31f;面临的挑战与问题&#x1f31f;AIGC未来发展 &#x1f31f;AIGC十大热门网站推荐&#xff1a; 文心…

吴恩达机器学习-实践实验室:协同过滤推荐系统(Collaborative Filtering Recommender Systems)

在本练习中&#xff0c;您将实现协作过滤&#xff0c;以构建电影推荐系统。 文章目录 1-概念2-推荐系统3-电影评分数据集4-协作过滤学习算法4.1协同过滤成本函数 5-学习电影推荐6-建议7-祝贺 软件包 我们将使用现在熟悉的NumPy和Tensorflow软件包。 import numpy as np import…

调用nltk分词库时出现nltk_data Error loading averaged_perceptron_tagger问题的解决办法

问题描述&#xff1a;运行时出现[nltk_data] Error loading averaged_perceptron_tagger&#xff0c;Name or service not known问题&#xff0c;详见下图。 由于这个问题最近总是困扰开发和调试工作&#xff0c;因此将彻底的解决办法记录如下&#xff0c;如下设置好就不需要漫…

【数据结构】07查找

查找 1. 基本概念2. 顺序表查找2.1 顺序查找2.2 顺序查找优化-哨兵 3. 有序表查找3.1 折半查找&#xff08;二分查找&#xff09; 4. 分块查找&#xff08;索引顺序查找&#xff09;5. Hash表&#xff08;散列表&#xff09;5.1 散列函数的设计5.2 代码实现5.2.1 初始化Hash表5…

装修后快速入住指南,除甲醛的10个小妙招。福州中宅装饰,福州装修

装修后除甲醛的方法有很多种&#xff0c;以下是一些常见的方法&#xff1a; 1. 通风 通风是最基本的除甲醛方法之一&#xff0c;打开窗户让空气流通&#xff0c;可以将室内的甲醛排出。可以在早晨和晚上空气质量较好的时候进行通风。 2. 植物吸收 一些植物如吊兰、常春藤、虎…

李廉洋;4.13黄金,原油最新资讯,下周一盘走势分析及策略。

美国杜克大学大宗商品研究教授Harvey表示&#xff0c;目前除了避险情绪外&#xff0c;“上涨惯性”也是促使黄金“疯涨”的原因。他表示&#xff1a;“目前不断涌入黄金市场的资金实际上在增加风险敞口&#xff0c;除了散户&#xff0c;对冲基金和其他机构投资者也加入了黄金热…

vue 百度地图 使用 vue-baidu-map 进行当前位置定位和范围展示

vue 百度地图 使用 vue-baidu-map 进行当前位置定位和范围展示&#xff08;考勤打卡&#xff09; 一、创建百度地图账号&#xff0c;获取秘钥二、 引入插件1、安装vue-baidu-map2、在main.js中引入 三、 简单使用 最近写项目的时候&#xff0c;做到了考勤打卡的模块内容&#x…

pbootcms百度推广链接打不开显示404错误页面

PbootCMS官方在2023年4月21日的版本更新中&#xff08;对应V3.2.5版本&#xff09;&#xff0c;对URL参数添加了如下判断 if(stripos(URL,?) ! false && stripos(URL,/?tag) false && stripos(URL,/?page) false && stripos(URL,/?ext_) false…

记一次http访问超时服务器端调试

问题&#xff1a;http访问服务器时没有返回&#xff0c;没有超时&#xff0c;一直在阻塞 处理过程&#xff1a;telnet端口能连上&#xff0c;服务端程序也不存在处理时间过长的情况。 说明tcp连接没问题。推测是客户端连接后再发起请求&#xff0c;服务端阻塞了。因为很多客户…

PrimeKG:为精准医学分析设计的多模态知识图谱

PrimeKG&#xff1a;为精准医学分析设计的多模态知识图谱 PrimeKG简介数据资源和覆盖范围构建方法和技术细节PrimeKG多模态知识图谱的概览构建PrimeKG的过程PrimeKG 数据 多模态特性和临床应用PrimeKG 设计逻辑 论文&#xff1a;https://www.nature.com/articles/s41597-023-01…

最齐全,最简单的免费SSL证书获取方法——实现HTTPS访问

一&#xff1a;阿里云 优势&#xff1a;大平台&#xff0c;在站长中知名度最高&#xff0c;提供20张免费单域名SSL证书 缺点&#xff1a;数量有限&#xff0c;并且只有单域名证书&#xff0c;通配符以及多域名没有免费版本。并且提供的单域名证书只有三个月的期限。 二&#…

GPDB技术内幕 - SEMI JOIN浅析

GPDB技术内幕 - SEMI JOIN浅析 SEMI JOIN顾名思义&#xff0c;半连接&#xff0c;相对于join字段来说&#xff0c;针对外表的一行记录&#xff0c;内表只要有一条满足&#xff0c;就输出外表记录。注意&#xff0c;这里是仅输出外表记录。GPDB中有几种实现方式&#xff0c;本文…