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实现)的更多相关文章

  1. 再谈多线程模型之生产者消费者(总结)(c++11实现)

    0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...

  2. 再谈多线程模型之生产者消费者(多生产者和单一消费者 )(c++11实现)

    0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...

  3. 再谈多线程模型之生产者消费者(单一生产者和多消费者 )(c++11实现)

    0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生产者消费 ...

  4. 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)

    0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现) 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现)[本文] 再谈多线程模型之生 ...

  5. 再谈多线程模型之生产者消费者(基础概念)(c++11实现)

    0.关于 为缩短篇幅,本系列记录如下: 再谈多线程模型之生产者消费者(基础概念)(c++11实现)[本文] 再谈多线程模型之生产者消费者(单一生产者和单一消费者)(c++11实现) 再谈多线程模型之生 ...

  6. Java 多线程基础(十二)生产者与消费者

    Java 多线程基础(十二)生产者与消费者 一.生产者与消费者模型 生产者与消费者问题是个非常典型的多线程问题,涉及到的对象包括“生产者”.“消费者”.“仓库”和“产品”.他们之间的关系如下: ①.生 ...

  7. Java 多线程详解(四)------生产者和消费者

    Java 多线程详解(一)------概念的引入:http://www.cnblogs.com/ysocean/p/6882988.html Java 多线程详解(二)------如何创建进程和线程: ...

  8. [Java基础] java多线程关于消费者和生产者

    多线程: 生产与消费 1.生产者Producer生产produce产品,并将产品放到库存inventory里:同时消费者Consumer从库存inventory里消费consume产品. 2.库存in ...

  9. Java多线程-同步:synchronized 和线程通信:生产者消费者模式

    大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...

随机推荐

  1. MAC下如何连接安卓(小米)手机进行互传文件?

    命令行: brew cask install android-file-transfer AndroidFileTransfer, 在andorid设备和您的mac电脑之间浏览和传输文件: 不论通过什 ...

  2. ubuntu终端ls颜色配置

    buntu中没有LS_COLORS,/etc/目录中也没有DIR_COLORS,所以这里使用dircolor命令加以解决 1. 利用dircolors命令,查看我们的系统当前的文件名称显示颜色的值,然 ...

  3. 深入理解动态规划DP

    通过最近对于一些算法题的思考,越来越发现动态规划方法的在时间上高效性,往往该问题可以轻松的找到暴力破解的方法,其时间复杂度却不尽人意.下面来看看几个常见的动态规划思路的经典问题 例一.有一段楼梯有10 ...

  4. “equals”有值 与 “==”存在 “equals”只是比较值是否相同,值传递,==地址传递,null==a,避免引发空指针异常,STRING是一个对象==null,对象不存在,str.equals("")对象存在但是包含字符‘''

    原文链接:http://www.cnblogs.com/lezhou2014/p/3955536.html "equals" 与 "==" "equa ...

  5. IO流中的字符输入输出流及try...catch处理流处理中的异常

    使用字节流读取中文的问题 import java.io.FileInputStream; import java.io.IOException; /* 使用字节流读取中文文件 1个中文 GBK:占用两 ...

  6. Rational Rose的安装及使用教程(包括菜单命令解释、操作向导说明、快捷命令说明)

    一.安装教程 我安装时用的是镜像文件,所以安装前需要辅助软件来处理镜像文件.我用到的是UltraISO.UltraISO中文名叫软碟通 是一款功能强大而又方便实用的光盘映像文件的制作/编辑/转换工具, ...

  7. 学习java 7.7

    学习内容: 多态转型:向上转型 Animal a = new Cat(); a.eat(); 向下转型 Cat c = (Cat)a; c.eat(); 抽象方法没有方法体,抽象类中有抽象方法 抽象类 ...

  8. Could not get a resource from the pool

    redis报错Could not get a resource from the pool情况是:1.可以连接redis2.可以keys *查看数据,但是发现key少了好多(其实原因就是大量的key过 ...

  9. ORACLE 加大日志文件

    --新建临时日志文件alter database add logfile group 4 ('/u01/app/oracle/oradata/orcl/redo04.log') size 10m;al ...

  10. 深入 char

    深入 char * ,char ** ,char a[ ] ,char *a[] 内核分类: c语言 2013-02-23 15:34 15176人阅读 评论(8) 收藏 举报Charcharchar ...