[C++]生产消费模型

2023-11-02

生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的

github源码路径:https://github.com/dangwei-90/Design-Mode

// 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

// 参考大话设计模式 - 生产消费模型

#include <iostream>
#include <vector>
#include <cstdlib>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>


#ifndef SAFE_DELETE
#define SAFE_DELETE(p) { if(p){delete(p); (p)=NULL;} }
#endif

static const int g_item_queue_size_rel = 3;                      // 队列实际大小
static const int g_item_queue_size = g_item_queue_size_rel + 1;  // 用于判断的队列满的逻辑上限
static const int g_item_to_produce = 10;                         // 待生产数量
std::mutex g_mutex;                                              // 用于多线程同步输出,防止日志混乱

struct ItemQueue {
  int item_buffer[g_item_queue_size];  // 生产消费缓冲区,生产的数据存到此处,消费者从此处拿数据。
  size_t read_position;                // 标记位,消费者从数组中获取数据的位置
  size_t write_position;               // 标记位,生产者生产的数据放到数组中
  std::mutex queue_mtx;                // 操作缓冲区的锁,防止缓冲区数据混乱
  std::condition_variable queue_not_full;   // 条件变量,表示缓存区是否已满
  std::condition_variable queue_not_empty;  // 条件变量,表示缓冲区是否为空
} g_item_queue;


// 生成产品的实现
void ProductItem(ItemQueue* iq, int item) {
  std::unique_lock<std::mutex> queue_lock(iq->queue_mtx);
  // 判断 queue 是否已满,如果已满,则 while 等待
  while (((iq->write_position + 1) % g_item_queue_size) == iq->read_position) {
    {
      std::lock_guard<std::mutex> lock(g_mutex);
      std::cout << "缓冲区满,等待..." << std::endl;
    }
    (iq->queue_not_full).wait(queue_lock);
  }

  // queue 不为空,继续写入产品
  (iq->item_buffer)[iq->write_position] = item;

  // 写入标记位加1
  (iq->write_position)++;

  if (iq->write_position == g_item_queue_size) {
    // 已满,设定写入位置为初始位置
    iq->write_position = 0;
  }

  (iq->queue_not_empty).notify_all(); // 通知消费者,队列不为空
  queue_lock.unlock();
}

// 消费产品的实现
int ConsumeItem(ItemQueue* iq) {
  int data = -1;
  std::unique_lock<std::mutex> queue_lock(iq->queue_mtx);
  // 判断 queue 是否为空,空的时候,等待
  while (iq->read_position == iq->write_position) {
    {
      std::lock_guard<std::mutex> lock(g_mutex);
      std::cout << "缓冲区空,等待..." << std::endl;
    }
    (iq->queue_not_empty).wait(queue_lock);
  }

  data = (iq->item_buffer)[iq->read_position]; // 读取产品

  (iq->read_position)++;

  if (iq->read_position == g_item_queue_size) {
    iq->read_position = 0;
  }

  (iq->queue_not_full).notify_all();
  queue_lock.unlock();

  return data;
}

// 生产者任务
void ProducerTask() {
  for (int n = 1; n <= g_item_to_produce; n++) {
    ProductItem(&g_item_queue, n);
    {
      std::lock_guard<std::mutex> lock(g_mutex);
      std::cout << "生成产品:" << n << " " << std::endl;
    }
  }
}

void ConsumerTask() {
  static int consume_count = 0;
  while (1) {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    int item = ConsumeItem(&g_item_queue);
    {
      std::lock_guard<std::mutex> lock(g_mutex);
      std::cout << "消费产品:" << item << " " << std::endl;
    }
    if (++consume_count == g_item_to_produce) {
      // 满足消费者数量后,退出
      break;
    }
  }
}

void  InitItemQueue(ItemQueue* iq) {
  iq->write_position = 0;
  iq->write_position = 0;
}

int main()
{
  InitItemQueue(&g_item_queue);
  std::thread producer_thread(ProducerTask);
  std::thread consumer_thread(ConsumerTask);

  producer_thread.join();
  consumer_thread.join();

	return 0;
}

 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

[C++]生产消费模型 的相关文章

  • leetcode:37. 解数独

    题目链接 37 解数独 文章目录 题目描述 思路 代码 题目描述 编写一个程序 通过填充空格来解决数独问题 数独的解法需 遵循如下规则 数字 1 9 在每一行只能出现一次 数字 1 9 在每一列只能出现一次 数字 1 9 在每一个以粗实线分
  • git lfs搭建 —— ubuntu20.04

    一直使用git lab 临时需要放一些pdf文档但有不需要git来版本管理 个人感觉比较占用资源 百度了一通 决定用git lfs 同时发现git lab有内置lfs使用说明 结合网上查得 总结如下 也是个人操作留档 本人使用vscode

随机推荐

  • 学生的姓名 ,年龄,性别,班级及爱好IDEA代码

    学生的姓名 年龄 性别 班级及爱好AIDE代码 package zy 学生类 class Person 属性 姓名 年龄 性别 班级 爱好 String name 姓名 int age 年龄 String sex 性别 int classN
  • 【数据结构】LoopQueue 循环队列

    数据结构源码 接口 public interface Queue
  • yarn安装依赖包报错 error An unexpected error occurred: “https://registry.npm.taobao.orgnpm/element-ui: get

    yarn安装依赖包报错 error An unexpected error occurred https registry npm taobao orgnpm element ui getaddrinfo ENOTFOUND registr
  • NAT(网络地址转换协议)

    目录 NAT 网络地址转换协议 作用 NAT转换内部地址范围 主要应用方向 NAT的优点 实验 1 静态NAT 一个内网地址对一个公网地址 2 动态NAT PAT 多个内网地址对多个公网地址 3 Easy ip 多个内网地址对一个接口 4
  • shell脚本实战:linux系统初始化和mysql8.0编译安装

    linux系统初始化脚本 bin bash version v1 author xingdian cat lt lt eof a 关闭防火墙 b 关闭selinux c 网络连通性检测 d 配置yum仓库 q 退出 eof read p 请
  • STM32 USB声卡录音(USB Microphone),基于CubeMX修改

    目录 说明 CubeMX配置 Pinout Clock Configuration Configuration 工程设置 代码工程修改 修改USB设备描述符 修改数据传输配置 声卡测试 说明 CubeMX生成的USB Audio Devic
  • Openwrt下安装Python3.5运行出现异常:Fatal Python error: Py_Initialize: Unable to get the locale encoding

    环境说明 Openwrt Python 3 5 依赖的库 libbz2 expat libopenssl libpthread zlib libffi libcrypto libncurses libpanel 使用说明 之前已经安装过py
  • OpenCV人脸识别

    OpenCV人脸识别与口罩检测 下载文件 人脸检测 人脸检测的检测方法主要有两类 基于知识 根据眼睛 眉毛 嘴巴 鼻子等器官特征及相互几何位置关系来检测 和基于统计 将人脸看作一个二维像素矩阵 通过大量人脸图像样本构造人脸模式空间 由相似度
  • kafka进阶

    kafka进阶 初识kafka 生产者 消费者 主题与分区 springboot kafka 集群 监控 面试题 初识kafka 消息队列 分布式发布 订阅消息系统 日志处理 基础架构 Producer 消息生产者 向Kafka中发布消息的
  • FSDirectory介绍

    其中常用的就是FSDirectory 表示对文件系统目录的操作 RAMDirectory 内存中的目录操作 首先我们看看类FSDirectory的源代码 import java io File import java io FileInpu
  • 2019完整的大数据知识体系,大数据学习路线图

    任何学习过程都需要一个科学合理的学习路线 才能够有条不紊的完成我们的学习目标 大数据所需学习的内容纷繁复杂 难度较大 有一个合理的大数据学习路线图帮忙理清思路就显得尤为必要 在这里还是要推荐下我自己建的大数据学习交流群 199427210
  • DL-深度学习基础

    目录 过拟合与欠拟合 降低过拟合风险的方法 降低欠拟合风险的方法 过拟合与欠拟合 欠拟合指模型不能在训练集上获得足够低的训练误差 过拟合指模型的训练误差与测试误差 泛化误差 之间差距过大 反应在评价指标上 就是模型在训练集上表现良好 但是在
  • Unity实战(11):项目非启动状态下使用代码批量替换材质

    目录 前言 配置环境 一 场景准备 二 代码演示 三 效果呈现 四 关于Resources Load 的说明 前言 本文内容为unity在编辑状态 非启动状态 下使用代码批量替换材质 该方法也适用于其他在编辑状态下对物体的操作需求 配置环境
  • Python15行代码实现免费发送手机短信,推送消息

    本文主要讲如何实现发送短信的功能 全部代码只用15行 实现的功能 通过代码定时给手机推送短信 短信内容可以自定义文字 当然你也可以去别的网站爬取每日心灵鸡汤 天气预报或其它信息进行推送 首先贴出实现的效果图 后面再分两步详细描述实现过程 第
  • Postman使用_接口导入导出

    文章目录 Postman导入数据 Collections导出数据 Environments导出数据 Postman导出所有数据 Postman导入数据 可以导入collections 接口集 Environments 环境配置 通过分享的链
  • 贪心、递归、递推以及动态规划算法的分析与对比

    算法导论 贪心算法 递归算法 动态规划算法总结 一般实际生活中我们遇到的算法分为四类 一 gt 判定性问题 二 gt 最优化问题 三 gt 构造性问题 四 gt 计算性问题 而今天所要总结的算法就是着重解决 最优化问题 算法之道 对三种算法
  • 【Java】基本类型之double(九)

    特征 double 数据类型是双精度 64 位 符合IEEE 754标准的浮点数 浮点数的默认类型为double类型 double类型同样不能表示精确的值 如货币 默认值是 0 0d 例子 double d1 123 4 精度 double
  • 重绘控件

    在Qt中 paintEvent方法是进行重绘的 只要出现以下几种情况 系统就会自动调用paintEvent方法 a 当窗口部件第一次显示时 系统会自动产生一个绘图事件 b 重新调整窗口部件大小 c 当窗口部件被其他部件遮挡 然后又再次显示出
  • 亲测微信小程序备案流程,微信小程序如何备案,微信小程序备案所需准备资料

    微信小程序为什么要备案 微信官方给出如下说明 1 若微信小程序未上架 自2023年9月1日起 微信小程序须完成备案后才可上架 2 若微信小程序已上架 请于2024年3月31日前完成备案 逾期未完成备案 平台将按照备案相关规定于2024年4月
  • [C++]生产消费模型

    生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题 生产者和消费者彼此之间不直接通讯 而通过阻塞队列来进行通讯 所以生产者生产完数据之后不用等待消费者处理 直接扔给阻塞队列 消费者不找生产者要数据 而是直接从阻塞队列里取 阻塞