C++ 实现生产者消费者模型 (线程同步、互斥锁、条件变量锁)详细注释

代码结构

  • 任务:这里用一个int类型的taskNumber代替任务
  • 任务队列类:封装了任务队列,存,取等操作。
  • 生产者工作函数:生产者执行的函数,向任务队列中添加任务,每个生产者生产3个任务
  • 消费者工作函数:消费者执行的函数,从任务队列中拿任务,如果5秒内一直没有任务,则销毁

C++实现代码

#include <stdio.h>
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <queue>
#include <condition_variable>
#include <unistd.h>
#include <chrono>
using namespace std;int taskNumber = 0; //任务class task_queue{
public:// 构造函数task_queue(int maxNum=10){this->maxNum = maxNum;}// 添加任务void add_task(int i){  //i为生产者编号myMutex.lock(); // 访问临界资源,加锁// 这里必须使用while而不是if,考虑以下情况:// A B两个线程同时因为任务队列满而阻塞,现在来了一个空位置,AB同时解除阻塞(因为我们用的是notify_all()函数唤醒所有线程)// 这时假设A抢到了互斥锁myMutex并添加任务,之后释放myMutex。这时B又抢到锁,但是还没有空位置,如果用if就会出错。所以需要while循环判断是否有任务while(q.size() == maxNum){ //如果任务队列已经满了condFull.wait(myMutex); //条件锁阻塞}q.push(++taskNumber); //添加任务condEmpty.notify_all(); //告知因为没有任务而被阻塞的消费者线程解除阻塞cout<<"【任务"<<taskNumber<<"】已经被【生产者"<<i<<"】添加到任务队列中"<<endl;myMutex.unlock(); //解锁sleep(1);}// 弹出任务bool get_task(int i){ //i为消费者编号myMutex.lock(); // 访问临界资源,加锁// 使用while而不是if的原因同上,如果条件锁的唤醒函数使用的是notify_one()函数,理论上可以使用ifwhile(q.empty()){ //任务队列为空,则等待cv_status flag =condEmpty.wait_for( myMutex, chrono::seconds(5)); //等待5秒if(flag == std::__1::cv_status::timeout){ //timeout表示5秒都没有任务cout<<"【子线程"<<i<<"】退出"<<endl;myMutex.unlock(); //这里要解锁,不然退出的线程会一直占用互斥锁导致死锁return false; // 等待5秒都没有任务要执行,则退出线程}}int x = q.front(); //取任务q.pop();condEmpty.notify_all(); //告知因为任务队列满而阻塞的生产者解除阻塞cout<<"【消费者"<<i<<"】正在执行【任务"<<x<<"】......"<<endl;myMutex.unlock(); //互斥锁解锁sleep(1);return true;}// 获得当前任务数目int get_task_num(){lock_guard<mutex>my_lock_guard(myMutex); //使用lockguard自动释放锁return (int)q.size();}// 获得最大任务数据int get_task_max_num(){lock_guard<mutex>my_lock_guard(myMutex); //使用lockguard自动释放锁return maxNum;}private:queue<int>q; //假设一个int代表一个任务taskint maxNum; //最大任务数mutex myMutex; // 临界资源互斥锁condition_variable_any condFull; // 任务队列满条件锁condition_variable_any condEmpty; // 任务队列空条件锁
};void producer_task(task_queue &q, int i){ // 生产者工作函数,每个生产者生产3个任务, i(0~4)代表生产者编号int num=3;while(num--){q.add_task(i);
//        sleep(1);}
}
void consumer_task(task_queue &q, int i){ // 消费者工作函数,消费者循环消费任务,如果5秒内没有任务则停止工作while(1){bool flag = q.get_task(i);
//        sleep(1);if(flag==false)break;}
}int main(){task_queue q(5); //最大任务数为5thread producer[5]; // 5个生产者对象thread consumer[5]; // 5个消费者对象for(int i=0;i<5;++i){
//        producer[i] = thread(&task_queue::add_task, &q, i,i); //给生产者指定任务
//        consumer[i] = thread(&task_queue::get_task, &q,i); //给消费者指定任务producer[i] = thread(producer_task, ref(q),i); //给生产者指定任务consumer[i] = thread(consumer_task, ref(q),i); //给消费者指定任务}for(int i=0;i<5;++i){ //主线程等待子线程执行完毕producer[i].join();consumer[i].join();}return 0;
}

运行结果:

尾部的运行结果,可以看出任务是按照添加的顺序执行的,在等待5秒之后,线程依次退出
在这里插入图片描述

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

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

相关文章

投票评选活动小程序v2-用户报名图片上传

投票评选活动小程序v2-用户自行报名收集材料页面 主要收集项目或者作品图片及其描述&#xff0c;可以在后台进行统一录入&#xff0c;也可以是在用户界面&#xff0c;让用户自行报名上传。 这里开发了一个“我要报名”页面&#xff0c;在首页点击“我要报名”按钮跳转过来。 …

小程序代码提审用户隐私保护协议修改指引

为规范开发者的用户个人信息处理行为&#xff0c;保障用户合法权益&#xff0c;小程序涉及处理用户个人信息的开发者&#xff0c;均需补充相应用户隐私保护指引&#xff1b;微信会根据小程序版本隐私接口调用情况展示必填项&#xff0c;开发者可自主勾选其他项目。 一、代码提…

SpringBoot 实现 elasticsearch 查询操作(RestHighLevelClient 的案例实战)

文章目录 1. 环境准备1. 查询全部2. 根据 name 查询 match 分词查询3. 根据 name 和 品牌查询 multiMatch 分词查询4. 根据 brand 查询 match 分词查询5. 按照价格 范围查询6. 精确查询7. boolQuery8. 分页9. 高亮查询9. 公共解析 上一节讲述了 SpringBoot 实现 elasticsearch …

小程序蓝牙通信

蓝牙通信能力封装 一开始是根据uniapp提供的蓝牙api写的蓝牙方法&#xff0c;之后发现复用性&#xff0c;以及一些状态的监听存在缺陷&#xff0c;之后整理成了类。这样复用性以及状态监听的问题就解决了。 蓝牙组件 创建蓝牙组件的类 单例模式是为了保证蓝牙长连接&#xff0…

(22)LED灯(外部)

文章目录 前言 22.1 带有I2C连接的RGB LEDs/显示器 22.2 串行连接的设备 22.3 NTF LED的含义 前言 外部 LED 或 LED 显示屏可以通过连接到自动驾驶仪的 I2C 端口&#xff0c;或者在 4.0 及以后的版本中&#xff0c;如果是串行编程的设备&#xff0c;可以通过输出使用 SERV…

Image Sensor的FSIN/VSYNC

本文介绍Image Sensor的FSIN/VSYNC。 产品开发过程(比如3D成像)中&#xff0c;有时会遇到需要2个及以上的Image Sensor同步采集&#xff0c;因此&#xff0c;Image Sensor厂家对于他们的产品都提供了同步功能&#xff0c;也就是我们经常所见的FSIN/VSYNC(OV),XVS(Sony IMX3系列…

gen1-视频生成论文阅读

文章目录 摘要贡献算法3.1 LDM3.2 时空隐空间扩散3.3表征内容及结构内容表征结构表征条件机制采样 3.4优化过程 实验结果结论 论文&#xff1a; 《Structure and Content-Guided Video Synthesis with Diffusion Models》 官网&#xff1a; https://research.runwayml.com/ge…

大象机器人myCobot 280 2023版全新功能展示

引言 机械臂是一种可编程的、自动化的机械系统&#xff0c;它可以模拟人类的动作&#xff0c;完成各种任务&#xff0c;例如装配、喷涂、包装、搬运、焊接、研磨等。由于其高度灵活性和多功能性&#xff0c;机械臂在现代社会中已经得到了广泛的应用。 myCobot 280 M5Stack 202…

Spring Boot 中的 SockJS

Spring Boot 中的 SockJS 在 Spring Boot 中&#xff0c;SockJS 是一个用于实现 WebSocket 的兼容性解决方案。本文将介绍 SockJS 的原理、使用方法和示例代码。 什么是 SockJS SockJS 是一种浏览器与服务器之间的通信协议&#xff0c;它可以在浏览器和服务器之间建立一个基于…

论文阅读:Segment Anything之阅读笔记

目录 引言整体结构介绍论文问答代码仓库中&#xff0c;模型哪部分转换为了ONNX格式&#xff1f;以及如何转的&#xff1f;Mask decoder部分 Transformer decoder block?如何整合image_embedding&#xff0c;image_pe, sparse_prompt_embedding和dense_prompt_embedding的&…

将OxyPlot封装成用户控件后在WPF中的应用

1、文件架构 2、加载依赖项 Newtonsoft.Json OxyPlot.Wpf 3、NotifyBase.cs namespace Accurate.Common {public class NotifyBase : INotifyPropertyChanged{public event PropertyChangedEventHandler? PropertyChanged;public void DoNotify([CallerMemberName] string p…

XR-FRAME 开始

目录 新建一个XR组件在页面中使用这个组件添加一个物体来点颜色和灯光有点寡淡&#xff0c;加上图像让场景更丰富&#xff0c;环境数据动起来&#xff0c;加入动画还是不够&#xff0c;放个模型再来点交互组件通信&#xff0c;加上HUD虚拟 x 现实&#xff0c;追加AR能力识别人脸…