当前位置: 首页 > news >正文

生产者消费者模型(多线程工作)

目录

1.模型前提

2.阻塞队列(消费场所)

3. 实验

4.有关效率


1.模型前提

以单生产者对单消费者为例子:

前提一:有一个缓冲区作为消费场所。

前提二:有两种功能不同的线程分别具有消费与生产的能力。

前提三:生产者与生产者之间有互斥的关系,消费者与消费者之间有互斥的关系,生产者与消费者之间同时具有互斥与同步的关系。


2.阻塞队列(消费场所)

阻塞队列与普通队列最大的不同是:当队列满时生产者不能继续生产,当队列空时消费者不能继续消费。


3. 实验

来展示一份多线程工作遵循生产者消费者模型的代码。

部分1:设置消费的模板(task.hpp)

#pragma once#include <iostream>
#include <functional>typedef std::function<int(int, int)> func_t;//c++11特性打包器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_;
};

 部分2:采用raii的方式设置锁的处置方式(lockGuard.hpp)

#pragma once#include <iostream>
#include <pthread.h>class Mutex 
{
public:Mutex(pthread_mutex_t *mtx):pmtx_(mtx){}void lock() {std::cout << "要进行加锁" << std::endl;pthread_mutex_lock(pmtx_);}void unlock(){std::cout << "要进行解锁" << std::endl;pthread_mutex_unlock(pmtx_);}~Mutex(){}
private:pthread_mutex_t *pmtx_;
};// RAII风格的加锁方式
class lockGuard
{
public://构造时加锁//析构时解锁lockGuard(pthread_mutex_t *mtx):mtx_(mtx){mtx_.lock();}~lockGuard(){mtx_.unlock();}
private:Mutex mtx_; //锁
};

这里解释一下为什么要加锁,因为要维护前提三,也就是要维护互斥的关系。

部分3:阻塞队列这个数据结构

#pragma once#include <iostream>
#include <queue>
#include <mutex>
#include <pthread.h>
#include "lockGuard.hpp"const int gDefaultCap = 5;template <class T>
class BlockQueue
{
private://判断队列的空与满bool isQueueEmpty(){return bq_.size() == 0;}bool isQueueFull(){return bq_.size() == capacity_;}public:BlockQueue(int capacity = gDefaultCap) : capacity_(capacity){pthread_mutex_init(&mtx_, nullptr);pthread_cond_init(&Empty_, nullptr);pthread_cond_init(&Full_, nullptr);}void push(const T &in) // 生产者{lockGuard lockgrard(&mtx_); // 自动调用构造函数//不停的检查直到队列非满while (isQueueFull())pthread_cond_wait(&Full_, &mtx_); //等待时会自动解锁,消费者可以消费bq_.push(in); //非满时可以插入任务(数据)pthread_cond_signal(&Empty_); //既然插入的数据,那么队列为空这个条件变量就可以解除了。} // 自动调用lockgrard 析构函数void pop(T *out){lockGuard lockguard(&mtx_);while (isQueueEmpty())pthread_cond_wait(&Empty_, &mtx_);*out = bq_.front();bq_.pop();pthread_cond_signal(&Full_);}~BlockQueue(){pthread_mutex_destroy(&mtx_);pthread_cond_destroy(&Empty_);pthread_cond_destroy(&Full_);}private:std::queue<T> bq_;     // 阻塞队列int capacity_;         // 容量上限pthread_mutex_t mtx_;  // 通过互斥锁保证队列安全pthread_cond_t Empty_; // 用它来表示bq 是否空的条件pthread_cond_t Full_;  //  用它来表示bq 是否满的条件
};

部分4:主程序部分,创建线程。

#include "BlockQueue.hpp"
#include "Task.hpp"#include <pthread.h>
#include <unistd.h>
#include <ctime>int myAdd(int x, int y) //设置了消费方式
{return x + y;
}void* consumer(void *args) //消费者
{BlockQueue<Task> *bqueue = (BlockQueue<Task> *)args;while(true){// 获取任务Task t;bqueue->pop(&t);// 完成任务std::cout << pthread_self() <<" consumer: "<< t.x_ << "+" << t.y_ << "=" << t() << std::endl;// sleep(1);}return nullptr;
}void* productor(void *args) //生产者
{BlockQueue<Task> *bqueue = (BlockQueue<Task> *)args;while(true){// 制作任务 -- 不一定是从生产者来的int x = rand()%10 + 1;usleep(rand()%1000);int y = rand()%5 + 1;Task t(x, y, myAdd);// 生产任务bqueue->push(t);// 输出消息std::cout <<pthread_self() <<" productor: "<< t.x_ << "+" << t.y_ << "=?" << std::endl;sleep(1);}return nullptr;
}int main()
{//生成随机数种子srand((uint64_t)time(nullptr) ^ getpid() ^ 0x32457);BlockQueue<Task> *bqueue = new BlockQueue<Task>();pthread_t c[2],p[2];//创建线程pthread_create(c, nullptr, consumer, bqueue);pthread_create(c + 1, nullptr, consumer, bqueue);pthread_create(p, nullptr, productor, bqueue);pthread_create(p + 1, nullptr, productor, bqueue);//销毁线程pthread_join(c[0], nullptr);pthread_join(c[1], nullptr);pthread_join(p[0], nullptr);pthread_join(p[1], nullptr);delete bqueue;return 0;
}

结果:

 没有问题,生产者生产一次消费者就消费一次,并且在这之间存在了加解锁的过程。


4.有关效率

有人可能会疑问“明明还是加锁了,那不是没有提升效率嘛”。

由于生产者与消费之间存在消费场所,就可以做到生产者生产的同时消费者从消费场所拿走数据进行消费。因此提升的不是生产者与消费者之间传递数据的速度,而是提升了生产者生产数据的效率与消费者消费数据的效率。

相关文章:

生产者消费者模型(多线程工作)

目录 1.模型前提 2.阻塞队列&#xff08;消费场所&#xff09; 3. 实验 4.有关效率 1.模型前提 以单生产者对单消费者为例子&#xff1a; 前提一&#xff1a;有一个缓冲区作为消费场所。 前提二&#xff1a;有两种功能不同的线程分别具有消费与生产的能力。 前提三&…...

InnoDB锁

1、共享排他锁 Shared and Exclusive Locks--共享锁&#xff08;SLock&#xff09;&#xff0c;允许持有该锁的事务读取一行数据--排它锁&#xff08;XLock&#xff09;&#xff0c;允许持有该锁的事务删除或者更新一行数据特性&#xff1a;--行级锁--如果一个事务持有当前行的…...

Java Stream、File、IO 超详细整理,适合新手入门

目录 Java Stream Java File Java IO Java Stream Java Stream 是 Java 8 中引入的一种新的抽象数据类型&#xff0c;它允许开发人员使用函数式编程的方式来处理集合数据。 使用 Java Stream 可以方便地进行过滤、映射、排序和聚合等操作。下面是一个简单的示例&#xff1a;…...

华为OD机试真题Python实现【寻找密码】真题+解题思路+代码(20222023)

寻找密码 题目 小王在进行游戏大闯关,有一个关卡需要输入一个密码才能通过,密码获得的条件如下: 在一个密码本中,每一页都有一个由 26 个小写字母组成的若干位密码, 从它的末尾开始依次去掉一位得到的新密码也在密码本中存在。 请输出符合要求的密码,如果由多个符合要求…...

springboot和springframework版本依赖关系

springboot和springframework版本依赖关系 springboot版本springframework版本发布时间1.0.x1.0.0.RELEASE4.0.3.RELEASE2014.041.0.1.RELEASE4.0.3.RELEASE2014.041.0.2.RELEASE4.0.3.RELEASE2014.041.1.x1.1.0.RELEASE4.0.5.RELEASE2014.061.1.1.RELEASE4.0.5.RELEASE2014.0…...

Java-多线程-增强篇-锁 强化 第一篇

今天我们来学一下锁 会持续保持更新 欢迎追更哈 Java - 多线程 - 锁和提升 第1篇 首先强调一点&#xff1a;Java多线程的锁都是基于对象的&#xff0c;Java中的每一个对象都可以作为一个锁。同时&#xff0c;类锁也是对象锁&#xff0c;类是Class对象 Java8锁 核心思想 关键…...

Java static+private实现单例模式

1. 单例模式介绍 在Java中单例设计模式准确来说是&#xff0c;类的单例设计模式&#xff0c;就是采取一定的方法保证在整个的软件系统中&#xff0c;对某个类只能存在一个对象实例&#xff0c;并且该类只提供一个取得其对象实例的方法。 2. 实现思路 如果我们要让类在一个虚…...

华为OD机试 - 查找充电设备组合(Python)【2023-Q1 新题】

华为OD机试300题大纲 参加华为od机试,一定要注意不要完全背诵代码,需要理解之后模仿写出,通过率才会高。 华为 OD 清单查看地址:blog.csdn.net/hihell/category_12199275.html 华为OD详细说明:https://dream.blog.csdn.net/article/details/128980730 查找充电设备组合…...

Authing 入选德勤“中国明日之星”企业榜单

近日&#xff0c;德勤发布“德勤中国明日之星”榜单&#xff0c;该项目致力于发掘和表彰蓬勃成长、持续创新、积极承担社会责任的卓越企业。该榜单1995 年创立至今&#xff0c;被业界誉为“全球高成长企业的标杆”。Authing 凭借在 IDaaS&#xff08;身份云&#xff09; 领域突…...

单片机嵌入式操作系统内核

1、前后台系统&#xff0c;协作式内核系统&#xff0c;与占先式内核系统&#xff0c;有什么不同呢&#xff1f; 记得在 21IC 上看过这样的比喻, 你(小工)在用厕所&#xff0c;经理在外面排第一&#xff0c;老板在外面排第二。 如果是前后台&#xff0c;不管是谁&#xff0c;都…...

C语言——柔性数组

目录0. 前言1. 思维导图2. 柔性数组的特点3. 柔性数组的使用4. 柔性数组的优势5. 结语0. 前言 柔性数组是在C99标准时引入&#xff1a; 结构中的最后一个元素允许是未知大小的数组&#xff0c;这就叫柔性数组成员。 代码示例&#xff1a; typedef struct flexible_arr {int a…...

web人脸登录

1&#xff0c;需要腾讯人脸第三方 腾讯人脸第三方申请步骤 2&#xff0c;相关表结构设计 create database faceDB;use faceDB; -- 人脸表 create table face( fid int primary key auto_increment COMMENT 主键, face_base longtext COMMENT 图片数据 base_64编码, create_tim…...

C++数字

目录 一、什么是数字 二、定义数字 三、数学运算 四、随机数 一、什么是数字 通常&#xff0c;当我们需要用到数字时&#xff0c;我们会使用原始的数据类型&#xff0c;如 int、short、long、float 和 double 等等。这些用于数字的数据类型&#xff0c;其可能的值和数值范围…...

【python】用plotly绘制正二十面体

文章目录顶点棱实现正二十面体plotly 的 Python 软件包是一个开源的代码库&#xff0c;它基于 plot.js&#xff0c;而后者基于 d3.js。我们实际使用的则是一个对 plotly 进行封装的库&#xff0c;名叫 cufflinks&#xff0c;能让你更方便地使用 plotly 和 Pandas 数据表协同工作…...

[Datawhale][CS224W]图机器学习(五)

这里写目录标题一、Deepwalk1.1 预备知识1.2 Deepwalk介绍1.3 Embedding1.4 word2Vec 词向量&#xff0c;词嵌入1.5 random Walk随机游走1.6 DeepWalk 核心代码Random WalkWord2vecDeepWalk应用1.7 DeepWalk优缺点二、Node2Vec2.1 图嵌入2.2 Node2Vec优化目标顶点序列采样策略2…...

Windows部署Jar包的三种方式

文章目录1、cmd命令启动2、bat脚本启动2.1 启动jar包2.2 关闭服务3、使用WinSW3.1 重命名3.2 xml配置3.3 安装服务3.4 卸载服务3.5 启动和停止服务1、cmd命令启动 这种方式比较简单&#xff0c;但是窗口关闭后服务也就被杀死了&#xff0c;命令如下 java -jar xxx.jar2、bat脚…...

【图像分类】卷积神经网络之AlexNet网络模型结构详解

写在前面: 首先感谢兄弟们的关注和订阅,让我有创作的动力,在创作过程我会尽最大能力,保证作品的质量,如果有问题,可以私信我,让我们携手共进,共创辉煌。 1. 前言 LeNet5网络模型提出之后,卷积神经网络在很长一段时间都没有长足的发展,主要有以下两个原因: 1.1 训…...

学习动漫插画的网络班排行榜

很多小伙伴不知道动漫插画培训机构哪个好&#xff0c;找不到靠谱的插画班&#xff0c;今天给大家整理了国内动漫插画培训机构排名&#xff01; 一&#xff1a;动漫插画培训机构排名 1、轻微课&#xff08;五颗星&#xff09; 主打课程有日系插画、游戏原画、古风插画、动漫漫画…...

SpringCloud第五讲 Nacos注册中心-服务注册到Nacos

1.引入依赖&#xff1a; 在父工程中添加spring-cloud-alibaba的管理依赖 <!-- Nacos的管理依赖--><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-dependencies</artifactId><version…...

IP地理位置定位技术原理是什么

IP地理位置定位技术的原理是基于IP地址的网络通信原理和基础上的。它利用IP地址所包含的一些信息&#xff0c;如网络前缀和地址段&#xff0c;以及ISP的IP地址归属地数据库&#xff0c;来推测IP地址所对应的地理位置。具体来说&#xff0c;IP地址是由32位二进制数字组成的&…...

【Linux】C语言执行shell指令

在C语言中执行Shell指令 在C语言中&#xff0c;有几种方法可以执行Shell指令&#xff1a; 1. 使用system()函数 这是最简单的方法&#xff0c;包含在stdlib.h头文件中&#xff1a; #include <stdlib.h>int main() {system("ls -l"); // 执行ls -l命令retu…...

mongodb源码分析session执行handleRequest命令find过程

mongo/transport/service_state_machine.cpp已经分析startSession创建ASIOSession过程&#xff0c;并且验证connection是否超过限制ASIOSession和connection是循环接受客户端命令&#xff0c;把数据流转换成Message&#xff0c;状态转变流程是&#xff1a;State::Created 》 St…...

ssc377d修改flash分区大小

1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...

《Playwright:微软的自动化测试工具详解》

Playwright 简介:声明内容来自网络&#xff0c;将内容拼接整理出来的文档 Playwright 是微软开发的自动化测试工具&#xff0c;支持 Chrome、Firefox、Safari 等主流浏览器&#xff0c;提供多语言 API&#xff08;Python、JavaScript、Java、.NET&#xff09;。它的特点包括&a…...

macOS多出来了:Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用

文章目录 问题现象问题原因解决办法 问题现象 macOS启动台&#xff08;Launchpad&#xff09;多出来了&#xff1a;Google云端硬盘、YouTube、表格、幻灯片、Gmail、Google文档等应用。 问题原因 很明显&#xff0c;都是Google家的办公全家桶。这些应用并不是通过独立安装的…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

uniapp微信小程序视频实时流+pc端预览方案

方案类型技术实现是否免费优点缺点适用场景延迟范围开发复杂度​WebSocket图片帧​定时拍照Base64传输✅ 完全免费无需服务器 纯前端实现高延迟高流量 帧率极低个人demo测试 超低频监控500ms-2s⭐⭐​RTMP推流​TRTC/即构SDK推流❌ 付费方案 &#xff08;部分有免费额度&#x…...

JVM暂停(Stop-The-World,STW)的原因分类及对应排查方案

JVM暂停(Stop-The-World,STW)的完整原因分类及对应排查方案,结合JVM运行机制和常见故障场景整理而成: 一、GC相关暂停​​ 1. ​​安全点(Safepoint)阻塞​​ ​​现象​​:JVM暂停但无GC日志,日志显示No GCs detected。​​原因​​:JVM等待所有线程进入安全点(如…...

Linux 内存管理实战精讲:核心原理与面试常考点全解析

Linux 内存管理实战精讲&#xff1a;核心原理与面试常考点全解析 Linux 内核内存管理是系统设计中最复杂但也最核心的模块之一。它不仅支撑着虚拟内存机制、物理内存分配、进程隔离与资源复用&#xff0c;还直接决定系统运行的性能与稳定性。无论你是嵌入式开发者、内核调试工…...

力扣热题100 k个一组反转链表题解

题目: 代码: func reverseKGroup(head *ListNode, k int) *ListNode {cur : headfor i : 0; i < k; i {if cur nil {return head}cur cur.Next}newHead : reverse(head, cur)head.Next reverseKGroup(cur, k)return newHead }func reverse(start, end *ListNode) *ListN…...