再谈多线程模型之生产者消费者(多生产者和多消费者 )(c++11实现)
0.关于
为缩短篇幅,本系列记录如下:
再谈多线程模型之生产者消费者(基础概念)(c++11实现)
再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)
再谈多线程模型之生产者消费者(单一生产者和多消费者)(c++11实现)
再谈多线程模型之生产者消费者(多生产者和单一消费者 )(c++11实现)
再谈多线程模型之生产者消费者(多生产者和多消费者 )(c++11实现)【本文】
再谈多线程模型之生产者消费者(总结)(c++11实现)
本文涉及到的代码演示环境: VS2017
欢迎留言指正
1. 多生产者&多消费者
- 1.1 相对一对一和一对多,多对多则是一对一和多对多的结合体。
- 1.2 生产者有多个,且其相互之间存在竞争
- 1.3 消费者有多个,其其相互之间存在竞争
- 1.4 大家共用一个缓冲区,还要考虑生产者与消费者之间的T同步情况。
- 1.5 结构体模型是这样的:
template<typename T>
struct repo_
{
// 用作互斥访问缓冲区
std::mutex _mtx_queue;
// 缓冲区最大size
unsigned int _count_max_queue_10 = 10;
// 缓冲区
std::queue<T> _queue;
// 缓冲区没有满,通知生产者继续生产
std::condition_variable _cv_queue_not_full;
// 缓冲区不为空,通知消费者继续消费
std::condition_variable _cv_queue_not_empty;
// 用于生产者之间的竞争
std::mutex _mtx_pro;
// 计算当前已经生产了多少数据了
unsigned int _cnt_cur_pro = 0;
// 用于消费者之间的竞争
std::mutex _mtx_con;
// 计算当前已经消费多少数据了
unsigned int _cnt_cur_con = 0;
repo_(const unsigned int count_max_queue = 10) :_count_max_queue_10(count_max_queue)
, _cnt_cur_con(0)
{
;
}
repo_(const repo_&instance) = delete;
repo_& operator = (const repo_& instance) = delete;
repo_(const repo_&&instance) = delete;
repo_& operator = (const repo_&& instance) = delete;
};
可见,相对单一消费者和单一生产者模型,多了下面的代码,用于解决竞争的问题。
// 用于生产者之间的竞争
std::mutex _mtx_pro;
// 计算当前已经生产了多少数据了
unsigned int _cnt_cur_pro = 0;
// 用于消费者之间的竞争
std::mutex _mtx_con;
// 计算当前已经消费多少数据了
unsigned int _cnt_cur_con = 0;
- 1.6 生产者线程
template< typename T >
void thread_pro(const int thread_index, const int count_max_produce, repo<T>* param_repo)
{
if (nullptr == param_repo || NULL == param_repo)
return;
while (true)
{
bool is_running = true;
{
// 用于生产者之间竞争
std::unique_lock<std::mutex> lock(param_repo->_mtx_pro);
// 缓冲区没有满,继续生产
if (param_repo->_cnt_cur_pro < cnt_total_10)
{
thread_produce_item<T>(thread_index, *param_repo, param_repo->_cnt_cur_pro);
++param_repo->_cnt_cur_pro;
}
else
is_running = false;
}
std::this_thread::sleep_for(std::chrono::microseconds(16));
if (!is_running)
break;
}
}
- 1.7 消费者线程
template< typename T >
void thread_con(const int thread_index, repo<T>* param_repo)
{
if (nullptr == param_repo || NULL == param_repo)
return;
while (true)
{
bool is_running = true;
{
std::unique_lock<std::mutex> lock(param_repo->_mtx_con);
// 还没消费到指定的数目,继续消费
if (param_repo->_cnt_cur_con < cnt_total_10)
{
thread_consume_item<T>(thread_index, *param_repo);
++param_repo->_cnt_cur_con;
}
else
is_running = false;
}
std::this_thread::sleep_for(std::chrono::microseconds(16));
// 结束线程
if ((!is_running))
break;
}
}
1.8 完整源码
#pragma once
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
#include <queue>
#include <vector>
std::mutex _mtx;
std::condition_variable _cv_not_full;
std::condition_variable _cv_not_empty;
const int max_queue_size_10 = 10;
enum
{
// 总生产数目
cnt_total_10 = 10,
};
template<typename T>
struct repo_
{
// 用作互斥访问缓冲区
std::mutex _mtx_queue;
// 缓冲区最大size
unsigned int _count_max_queue_10 = 10;
// 缓冲区
std::queue<T> _queue;
// 缓冲区没有满,通知生产者继续生产
std::condition_variable _cv_queue_not_full;
// 缓冲区不为空,通知消费者继续消费
std::condition_variable _cv_queue_not_empty;
// 用于生产者之间的竞争
std::mutex _mtx_pro;
// 计算当前已经生产了多少数据了
unsigned int _cnt_cur_pro = 0;
// 用于消费者之间的竞争
std::mutex _mtx_con;
// 计算当前已经消费多少数据了
unsigned int _cnt_cur_con = 0;
repo_(const unsigned int count_max_queue = 10) :_count_max_queue_10(count_max_queue)
, _cnt_cur_con(0)
{
;
}
repo_(const repo_&instance) = delete;
repo_& operator = (const repo_& instance) = delete;
repo_(const repo_&&instance) = delete;
repo_& operator = (const repo_&& instance) = delete;
};
template <typename T>
using repo = repo_<T>;
//----------------------------------------------------------------------------------------
// 生产者生产数据
template <typename T>
void thread_produce_item(const int &thread_index, repo<T>& param_repo, const T& repo_item)
{
std::unique_lock<std::mutex> lock(param_repo._mtx_queue);
// 1. 生产者只要发现缓冲区没有满, 就继续生产
param_repo._cv_queue_not_full.wait(lock, [&] { return param_repo._queue.size() < param_repo._count_max_queue_10; });
// 2. 将生产好的商品放入缓冲区
param_repo._queue.push(repo_item);
// log to console
std::cout << "生产者" << thread_index << "生产数据:" << repo_item << "\n";
// 3. 通知消费者可以消费了
//param_repo._cv_queue_not_empty.notify_one();
param_repo._cv_queue_not_empty.notify_one();
}
//----------------------------------------------------------------------------------------
// 消费者消费数据
template <typename T>
T thread_consume_item(const int thread_index, repo<T>& param_repo)
{
std::unique_lock<std::mutex> lock(param_repo._mtx_queue);
// 1. 消费者需要等待【缓冲区不为空】的信号
param_repo._cv_queue_not_empty.wait(lock, [&] {return !param_repo._queue.empty(); });
// 2. 拿出数据
T item;
item = param_repo._queue.front();
param_repo._queue.pop();
std::cout << "消费者" << thread_index << "从缓冲区中拿出一组数据:" << item << std::endl;
// 3. 通知生产者,继续生产
param_repo._cv_queue_not_full.notify_one();
return item;
}
//----------------------------------------------------------------------------------------
/**
* @ brief: 生产者线程
* @ thread_index - 线程标识,区分是哪一个线程
* @ count_max_produce - 最大生产次数
* @ param_repo - 缓冲区
* @ return - void
*/
template< typename T >
void thread_pro(const int thread_index, const int count_max_produce, repo<T>* param_repo)
{
if (nullptr == param_repo || NULL == param_repo)
return;
while (true)
{
bool is_running = true;
{
// 用于生产者之间竞争
std::unique_lock<std::mutex> lock(param_repo->_mtx_pro);
// 缓冲区没有满,继续生产
if (param_repo->_cnt_cur_pro < cnt_total_10)
{
thread_produce_item<T>(thread_index, *param_repo, param_repo->_cnt_cur_pro);
++param_repo->_cnt_cur_pro;
}
else
is_running = false;
}
std::this_thread::sleep_for(std::chrono::microseconds(16));
if (!is_running)
break;
}
}
/**
* @ brief: 消费者线程
* @ thread_index - 线程标识,区分线程
* @ param_repo - 缓冲区
* @ return - void
*/
template< typename T >
void thread_con(const int thread_index, repo<T>* param_repo)
{
if (nullptr == param_repo || NULL == param_repo)
return;
while (true)
{
bool is_running = true;
{
std::unique_lock<std::mutex> lock(param_repo->_mtx_con);
// 还没消费到指定的数目,继续消费
if (param_repo->_cnt_cur_con < cnt_total_10)
{
thread_consume_item<T>(thread_index, *param_repo);
++param_repo->_cnt_cur_con;
}
else
is_running = false;
}
std::this_thread::sleep_for(std::chrono::microseconds(16));
// 结束线程
if ((!is_running))
break;
}
}
// 入口函数
//----------------------------------------------------------------------------------------
int main(int argc, char *argv[], char *env[])
{
// 缓冲区
repo<int> repository;
// 线程池
std::vector<std::thread> vec_thread;
// 生产者
vec_thread.push_back(std::thread(thread_pro<int>, 1, cnt_total_10, &repository));
vec_thread.push_back(std::thread(thread_pro<int>, 2, cnt_total_10, &repository));
// 消费者
vec_thread.push_back(std::thread(thread_con<int>, 1, &repository));
vec_thread.push_back(std::thread(thread_con<int>, 2, &repository));
for (auto &item : vec_thread)
{
item.join();
}
return 0;
}
- 1.9 可能的结果

再谈多线程模型之生产者消费者(多生产者和多消费者 )(c++11实现)的更多相关文章
- 再谈多线程模型之生产者消费者(总结)(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...
- 再谈多线程模型之生产者消费者(多生产者和单一消费者 )(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...
- 再谈多线程模型之生产者消费者(单一生产者和多消费者 )(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...
- 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)[本文] 再谈多线程模型之生 ...
- 再谈多线程模型之生产者消费者(基础概念)(c++11实现)
0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现)[本文] 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生 ...
- Java 多线程基础(十二)生产者与消费者
Java 多线程基础(十二)生产者与消费者 一.生产者与消费者模型 生产者与消费者问题是个非常典型的多线程问题,涉及到的对象包括“生产者”.“消费者”.“仓库”和“产品”.他们之间的关系如下: ①.生 ...
- Java 多线程详解(四)------生产者和消费者
Java 多线程详解(一)------概念的引入:http://www.cnblogs.com/ysocean/p/6882988.html Java 多线程详解(二)------如何创建进程和线程: ...
- [Java基础] java多线程关于消费者和生产者
多线程: 生产与消费 1.生产者Producer生产produce产品,并将产品放到库存inventory里:同时消费者Consumer从库存inventory里消费consume产品. 2.库存in ...
- Java多线程-同步:synchronized 和线程通信:生产者消费者模式
大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...
随机推荐
- 深入理解 OpenFOAM 环境变量与编译
操作系统选择 由于 OpenFOAM 在 Linux 平台开发和测试,在非 Linux 平台无法直接对软件进行编译和安装,所以在非 Linux 平台上最简便方法是使用 docker 容器运行 Open ...
- 从零构建Java项目(Maven+SpringBoot+Git) #02 奥斯丁项目
前两天我说要写个项目来持续迭代,有好多小伙伴都表示支持和鼓励,项目的第一篇这不就来了么~我给项目取了个名字,英文名叫做:austin,中文名叫做:奥斯丁 名字倒没有什么特别的含义,我单纯觉得这个名字好 ...
- binlog真的是银弹吗?有些时候也让人头疼
大家好,我是架构摆渡人.这是实践经验系列的第三篇文章,这个系列会给大家分享很多在实际工作中有用的经验,如果有收获,还请分享给更多的朋友. binlog 用于记录用户对数据库操作的SQL语句信息,同时主 ...
- day04 orm操作
day04 orm操作 昨日内容回顾 小白必会三板斧 request对象方法 静态文件 请求方式 python链接数据库 django链接数据库 小白必会三板斧 HttpResponse :返回前端浏 ...
- day07 Nginx入门
day07 Nginx入门 Nginx简介 Nginx是一个开源且高性能.可靠的http web服务.代理服务 开源:直接获取源代码 高性能:支持海量开发 可靠:服务稳定 特点: 1.高性能.高并发: ...
- day02 Rsyuc备份服务器
day02 Rsyuc备份服务器 一.备份 1.什么是备份 备份就是把重要的数据或者文件复制一份保存到另一个地方,实现不同主机之间的数据同步 一般数据比较重要的情况下,数据如果丢失很容易找不回来了的, ...
- Java实现 HTTP/HTTPS请求绕过证书检测
java实现 HTTP/HTTPS请求绕过证书检测 一.Java实现免证书访问Https请求 创建证书管理器类 import java.security.cert.CertificateExcepti ...
- go channel 概述 - 管道
概述 unix/linux OS 的一个进程的输出可以是另一个进程的输入,这些进程使用stdin与stdout设备作为通道,在进程之间传递数据. 同样的,GO中有io.Reader与io.Writer ...
- Spring中的InitializingBean与DisposableBean
InitializingBean顾名思义,应该是初始化Bean相关的接口. 先看一下该接口都定义了哪些方法: public interface InitializingBean { void afte ...
- spring cloud 通过 ribbon 实现客户端请求的负载均衡(入门级)
项目结构 环境: idea:2020.1 版 jdk:8 maven:3.6.2 1. 搭建项目 ( 1 )父工程:spring_cloud_demo_parent pom 文件 <?xml v ...