【C++并发编程】(十)生产者-消费者模型

(十)生产者-消费者模型

生产者-消费者模型是一种经典的并发编程模型,旨在解决多线程环境中负责生成数据或任务的线程(生产者)与负责处理数据或任务的线程(消费者)之间的协作与数据共享问题。生产者-消费者模型的关键要素包括:

  • 共享缓冲区:用于存放由生产者生产,被消费者处理的数据或任务。这个缓冲区通常是一个队列。

  • 同步机制:用于确保生产者和消费者线程之间的有效协调和数据安全共享。

单消费者-单生产者示例

下面的示例实现了一个单生产者-单消费者模型,以 std::queue 作为共享缓冲区,并通过 std::mutexstd::condition_variable 实现线程的同步。

#include <iostream>            
#include <queue>             
#include <thread>             
#include <mutex>              
#include <condition_variable> 

std::queue<int> buffer;             // 生产者消费者共享的缓冲区,用来存放数据或任务
const int max_buffer_size = 10;     // 缓冲区最大容量
std::mutex mtx;                     // 保护共享资源的互斥锁,确保在同一时间只有一个线程可以访问缓冲区
std::condition_variable cv_producer, cv_consumer;  // 生产者和消费者的条件变量
bool finished = false;              // 标记生产者是否已经完成

void producer() {
    for (int i = 1; i <= 20; ++i) {
        std::unique_lock<std::mutex> lock(mtx);  // 获取互斥锁
        cv_producer.wait(lock, []{ return buffer.size() < max_buffer_size; });  // 等待直到缓冲区有空间

        buffer.push(i);  // 生产一个数据并放入缓冲区
        std::cout << "Produced: " << i << std::endl;  

        cv_consumer.notify_one();  // 通知消费者有新数据可用
    }
   
    std::unique_lock<std::mutex> lock(mtx);
    finished = true;                 // 设置生产者已完成标志
    cv_consumer.notify_all();        // 通知所有消费者
}

void consumer() {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);  // 获取互斥锁
        cv_consumer.wait(lock, []{ return !buffer.empty() || finished; });  // 等待直到缓冲区不为空或生产者已完成

        if (buffer.empty() && finished) {
            break;  // 如果缓冲区为空且生产者已完成,退出循环
        }

        int item = buffer.front();  // 从缓冲区消费一个数据
        buffer.pop();  // 移除已消费的数据
        std::cout << "Consumed: " << item << std::endl; 

        cv_producer.notify_one();  // 通知生产者缓冲区有空间
    }
}

int main() {
    std::thread producer_thread(producer);  
    std::thread consumer_thread(consumer); 

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

    return 0; 
}


Produced: 1
Produced: 2
Produced: 3
Produced: 4
Produced: 5
Produced: 6
Produced: 7
Produced: 8
Produced: 9
Produced: 10
Consumed: 1
Consumed: 2
Consumed: 3
Consumed: 4
Consumed: 5
Consumed: 6
Consumed: 7
Consumed: 8
Consumed: 9
Consumed: 10
Produced: 11
Produced: 12
Produced: 13
Produced: 14
Produced: 15
Produced: 16
Produced: 17
Produced: 18
Produced: 19
Produced: 20
Consumed: 11
Consumed: 12
Consumed: 13
Consumed: 14
Consumed: 15
Consumed: 16
Consumed: 17
Consumed: 18
Consumed: 19
Consumed: 20

多生产者-多消费者示例

在实际应用中,通常会有多个消费者来处理多个生产者生成的数据。这种设置可以提高系统的并发性和吞吐量。以下是一个多生产者-多消费者模型的示例:

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

const int max_buffer_size = 10;
std::queue<int> buffer;
std::mutex mtx;
std::condition_variable cv_producer, cv_consumer;
int next_item = 1;  // 共享的生产数据计数器
bool should_quit = false;  // 共享的退出标志

void producer(int id) {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);  // 获取互斥锁
        cv_producer.wait(lock, []{ return buffer.size() < max_buffer_size || should_quit; });  // 等待直到缓冲区有空间或需要退出

        if (should_quit) break;  // 如果需要退出,则退出生产者线程

        buffer.push(next_item);  // 生产一个数据并放入缓冲区
        std::cout << "Producer " << id << " produced: " << next_item << std::endl;
        next_item++;

        cv_consumer.notify_one();  // 通知消费者有新数据可用

        if (next_item > 40) {  // 达到生产40个任务后设置退出标志
            should_quit = true;
            cv_consumer.notify_all();  // 唤醒所有消费者线程以检查退出条件
        }
    }
}

void consumer(int id) {
    while (true) {
        std::unique_lock<std::mutex> lock(mtx);  // 获取互斥锁
        cv_consumer.wait(lock, []{ return !buffer.empty() || should_quit; });  // 等待直到缓冲区不为空或需要退出

        if (buffer.empty() && should_quit) break;  // 如果需要退出且缓冲区为空,则退出消费者线程

        int item = buffer.front();  // 从缓冲区消费一个数据
        buffer.pop();  // 移除已消费的数据
        std::cout << "Consumer " << id << " consumed: " << item << std::endl;

        cv_producer.notify_one();  // 通知生产者缓冲区有空间
    }
}

int main() {
    std::thread producer1(producer, 1);
    std::thread producer2(producer, 2);

    std::vector<std::thread> consumers;
    for (int i = 1; i <= 3; ++i) {
        consumers.emplace_back(consumer, i);
    }

    // 等待生产者完成任务
    producer1.join();
    producer2.join();

    // 等待消费者完成任务
    for (auto& consumer : consumers) {
        consumer.join();
    }

    return 0;
}
Producer 1 produced: 1
Consumer 3 consumed: 1
Producer 1 produced: 2
Consumer 3 consumed: 2
Producer 2 produced: 3
Consumer 2 consumed: 3
Producer 1 produced: 4
Producer 1 produced: 5
Consumer 2 consumed: 4
Consumer 2 consumed: 5
Producer 1 produced: 6
Producer 1 produced: 7
Consumer 3 consumed: 6
Consumer 3 consumed: 7
Producer 1 produced: 8
Consumer 3 consumed: 8
Producer 2 produced: 9
Consumer 2 consumed: 9
Producer 2 produced: 10
Consumer 2 consumed: 10
Producer 2 produced: 11
Consumer 3 consumed: 11
Producer 2 produced: 12
Consumer 1 consumed: 12
Producer 1 produced: 13
Consumer 2 consumed: 13
Producer 2 produced: 14
Consumer 3 consumed: 14
Producer 2 produced: 15
Consumer 2 consumed: 15
Producer 2 produced: 16
Consumer 3 consumed: 16
Producer 2 produced: 17
Producer 2 produced: 18
Consumer 2 consumed: 17
Consumer 2 consumed: 18
Producer 2 produced: 19
Consumer 3 consumed: 19
Producer 1 produced: 20
Consumer 2 consumed: 20
Producer 1 produced: 21
Consumer 2 consumed: 21
Producer 1 produced: 22
Producer 1 produced: 23
Consumer 1 consumed: 22
Consumer 1 consumed: 23
Producer 1 produced: 24
Producer 1 produced: 25
Producer 1 produced: 26
Producer 1 produced: 27
Producer 1 produced: 28
Producer 1 produced: 29
Consumer 1 consumed: 24
Consumer 1 consumed: 25
Consumer 1 consumed: 26
Consumer 1 consumed: 27
Consumer 1 consumed: 28
Consumer 1 consumed: 29
Producer 2 produced: 30
Consumer 1 consumed: 30
Producer 2 produced: 31
Consumer 1 consumed: 31
Producer 2 produced: 32
Consumer 3 consumed: 32
Producer 2 produced: 33
Producer 2 produced: 34
Consumer 1 consumed: 33
Consumer 1 consumed: 34
Producer 2 produced: 35
Consumer 3 consumed: 35
Producer 1 produced: 36
Consumer 1 consumed: 36
Producer 1 produced: 37
Consumer 1 consumed: 37
Producer 1 produced: 38
Consumer 3 consumed: 38
Producer 1 produced: 39
Consumer 2 consumed: 39
Producer 1 produced: 40
Consumer 2 consumed: 40

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

初识c++(命名空间,缺省参数,函数重载)

一、命名空间 1、namespace的意义 在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存在于全 局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化&#xff0c;以避免命名 冲突…

python对象

类 我们目前所学习的对象都是Python内置的对象但是内置对象并不能满足所有的需求&#xff0c;所以我们在开发中经常需要自定义一些对象类&#xff0c;简单理解它就相当于一个图纸。在程序中我们需要根据类来创建对象类就是对象的图纸&#xff01;我们也称对象是类的实例&#…

caeses软件许可优化解决方案

Caeses软件介绍 CAESES是一款十分很不错的三维建模仿真的软件。它功能很大、优化效率高、可以自动化优化、分析工具快速 CAESES拥有多种不同的试验设计及单目标、多目标优化算法&#xff0c;能够根据仿真计算评估的结果。软件可以帮助用户轻松的打造出自各种船舶、汽车、航空航…

grafana数据展示

目录 一、安装步骤 二、如何添加喜欢的界面 三、自动添加注册客户端主机 一、安装步骤 启动成功后 可以查看端口3000是否启动 如果启动了就在浏览器输入IP地址&#xff1a;3000 账号密码默认是admin 然后点击 log in 第一次会让你修改密码 根据自定义密码然后就能登录到界面…

1-3分钟爆款视频素材在哪找啊?这9个热门爆款素材网站分享给你

在如今快节奏的时代&#xff0c;短视频已成为吸引观众注意力的黄金手段。然而&#xff0c;要制作出1-3分钟的爆款视频&#xff0c;除了创意和剪辑技巧外&#xff0c;选择合适的素材至关重要。那么&#xff0c;哪里可以找到那些能让你的视频脱颖而出的爆款素材呢&#xff1f;不用…

顶会FAST24最佳论文|阿里云块存储架构演进的得与失-1.引言

今年早些时候&#xff0c;2月份举办的全球计算机存储顶会USENIX FAST 2024&#xff0c;最佳论文来自阿里云&#xff0c;论文名称《What’s the Story in EBS Glory: Evolutions and Lessons in Building Cloud Block Store》 &#xff0c;论文详尽地探讨了阿里云在过去十年中开…

ASAN排查程序中内存问题使用总结

简介 谷歌有一系列Sanitizer工具&#xff0c;可用于排查程序中内存相关的问题。常用的Sanitizer工具包括&#xff1a; Address Sanitizer&#xff08;ASan&#xff09;&#xff1a;用于检测内存使用错误。Leak Sanitizer&#xff08;LSan&#xff09;&#xff1a;用于检测内存…

YOLOv9:一个关注信息丢失问题的目标检测

本文来自公众号“AI大道理” 当前的深度学习方法关注的是如何设计最合适的目标函数&#xff0c;使模型的预测结果最接近地面的真实情况。同时&#xff0c;必须设计一个适当的体系结构&#xff0c;以方便获取足够的预测信息。 现有方法忽略了一个事实&#xff0c;即输入数据在逐…

docker安装以及简单使用

如何安装安装 yum install -y yum-utils yum-config-manager --add-repo https://mirrors.aliyun.com/docker-ce/linux/centos/docker-ce.repo # 列出可用的版本 yum list docker-ce.x86_64 --showduplicates | sort -r yum install -y docker-ce-23.0.6-1.el8 #开机自动启动 …

Yolov10训练,转化onnx,推理

yolov10对于大目标的效果好&#xff0c;小目标不好 一、如果你训练过yolov5&#xff0c;yolov8&#xff0c;的话那么你可以直接用之前的环境就行 目录 一、如果你训练过yolov5&#xff0c;yolov8&#xff0c;的话那么你可以直接用之前的环境就行 二、配置好后就可以配置文件…

DBA 数据库管理

数据库&#xff1a;存储数据的仓库 数据库服务软件&#xff1a; 关系型数据库&#xff1a; 存在硬盘 &#xff0c;制作表格的 数据库的参数 [rootmysql50 ~]# cat /etc/my.cnf.d/mysql-server.cnf 主配置文件 [mysqld] datadir/var/lib/mysql 存放数据库目录…

黑马点评商户缓存查询作业——Redis中查询商户类型

记录下自己在gpt帮助下完成的第一个需求~~~ 1. ShopTypeController 2. IShopTypeService 3. ShopTypeServiceImpl&#xff08;模仿ShopServiceImpl来写的&#xff09; 一共分为“1.redis中查询缓存”→“2.判断缓存是否存在&#xff0c;存在直接返回”→“3.缓存不存在则去查数…

sql盲注

文章目录 布尔盲注时间盲注 布尔盲注 介绍&#xff1a;在网页只给你两种回显的时候是用&#xff0c;类似于布尔类型的数据&#xff0c;1表示正确&#xff0c;0表示错误。 特点&#xff1a;思路简单&#xff0c;步骤繁琐且麻烦。 核心函数&#xff1a; length()函数substr()函…

【MYSQL】如何解决 bin log 与 redo log 的一致性问题

该问题问的其实就是redo log 的两阶段提交 为什么说redo log 具有崩溃恢复的能力 MySQL Server 层拥有的 bin log 只能用于归档&#xff0c;不足以实现崩溃恢复&#xff08;crash-safe&#xff09;&#xff0c;需要借助 InnoDB 引擎的 redo log 才能拥有崩溃恢复的能力。所谓崩…

【AutoencoderKL】基于stable-diffusion-v1.4的vae对图像重构

模型地址&#xff1a;https://huggingface.co/CompVis/stable-diffusion-v1-4/tree/main/vae 主要参考:Using-Stable-Diffusion-VAE-to-encode-satellite-images sd1.4 vae 下载到本地 from diffusers import AutoencoderKL from PIL import Image import torch import to…

第二证券:资金抱团“高股息”,超三成A股年内创历史新低!

A股商场行情冰火两重天。 “预制菜榜首股”跌破发行价 7月8日&#xff0c;味知香盘中最低跌至19.26元/股&#xff0c;股价跌破发行价&#xff0c;并创前史新低。揭露资料显现&#xff0c;公司是集研发、生产、销售为一体的半成品菜企业&#xff0c;现在具有8大产品系列&#…

九科bit-Worker RPA 内容学习

简介&#xff1a; 什么是RPA&#xff1f; RPA&#xff08;Robotic Process Automation&#xff0c;机器人流程自动化&#xff09;本质上是一种“AI数字员工”&#xff0c;针对企业中存在的大批量、重复性、机械化人工操作&#xff0c;通过模拟人的工作流程使之实现自动化。 b…

Java | Leetcode Java题解之第219题存在重复元素II

题目&#xff1a; 题解&#xff1a; class Solution {public boolean containsNearbyDuplicate(int[] nums, int k) {Set<Integer> set new HashSet<Integer>();int length nums.length;for (int i 0; i < length; i) {if (i > k) {set.remove(nums[i - …

【小鸡案例】表单focus和blur事件用法

input中有2个属性&#xff0c;一个是focus获取焦点&#xff0c;一个是blur失去焦点。获取焦点就是我们点击输入框时输入框被选中&#xff1b;失去焦点即点击输入框以外的区域&#xff0c;今天就用这两种属性做一个点击输入框的动画效果。 先写个输入框&#xff0c;代码如下&am…

【leetcode周赛记录——405】

405周赛记录 #1.leetcode100339_找出加密后的字符串2.leetcode100328_生成不含相邻零的二进制字符串3.leetcode100359_统计X和Y频数相等的子矩阵数量4.leetcode100350_最小代价构造字符串 刷了一段时间算法了&#xff0c;打打周赛看看什么水平了 #1.leetcode100339_找出加密后的…