C++11 实现生产者消费者双缓冲
基础的生产者消费者模型,生产者向公共缓存区写入数据,消费者从公共缓存区读取数据进行处理,两个线程访问公共资源,加锁实现数据的一致性。
通过加锁来实现
class Produce_1 {
public:
Produce_1(std::queue<int> * que_, std::mutex * mt_) {
m_mt = mt_;
m_que = que_;
m_stop = false;
}
void runProduce() {
while (!m_stop) {
std::this_thread::sleep_for(std::chrono::seconds());
std::lock_guard<std::mutex> lgd(*m_mt);
m_que->push();
std::cout << "Produce_1 produce 1" << std::endl;
}
}
void join() {
m_trd->join();
m_trd.reset();
}
void start() {
m_trd.reset(new std::thread(std::bind(std::mem_fun(&Produce_1::runProduce), this)));
}
void stop() {
m_stop = true;
}
private:
std::mutex * m_mt;
std::queue<int> * m_que;
volatile bool m_stop;
std::shared_ptr<std::thread> m_trd;
}; /*
*单缓冲一个同步队列 效率较低
*/
class Consume_1 {
public:
Consume_1(std::queue<int> * que_, std::mutex * mt_) {
m_mt = mt_;
m_que = que_;
m_stop = false;
} void runConsume() {
while (!m_stop) {
std::this_thread::sleep_for(std::chrono::seconds());
std::lock_guard<std::mutex> lgd(*m_mt);
if (!m_que->empty()) {
m_que->pop();
}
std::cout << "Consume_1 consume" << std::endl;
}
}
void join() {
m_trd->join();
m_trd.reset();
}
void start() {
m_trd.reset(new std::thread(std::bind(std::mem_fun(&Consume_1::runConsume), this)));
}
void stop() {
m_stop = true;
}
private:
std::mutex * m_mt;
std::queue<int> * m_que;
volatile bool m_stop;
std::shared_ptr<std::thread> m_trd;
};
通过条件变量来实现
typedef struct Mutex_Condition{
std::mutex mt;
std::condition_variable cv;
}Mutex_Condition; class Produce {
public:
Produce(std::queue<int> * que_, Mutex_Condition * mc_) {
m_que = que_;
m_mc = mc_;
m_stop = false;
}
void join() {
m_trd->join();
m_trd.reset();
}
void produce(int enter) {
std::lock_guard<std::mutex> lgd(m_mc->mt);
m_que->push(enter);
m_mc->cv.notify_one();
} void runProduce() {
while (!m_stop) {
std::this_thread::sleep_for(std::chrono::seconds());
produce();
std::cout << "Produce Thread produce 1 " << std::endl;
}
} void start() {
m_trd.reset(new std::thread(std::bind(std::mem_fun(&Produce::runProduce), this)));
}
void stop() {
m_stop = true;
} private:
std::queue<int> * m_que;
Mutex_Condition * m_mc;
std::shared_ptr<std::thread> m_trd;
volatile bool m_stop;
}; class Consume {
public:
Consume(std::queue<int> * que_, Mutex_Condition * mc_) {
m_que = que_;
m_mc = mc_;
m_stop = false;
}
void join() {
m_trd->join();
m_trd.reset();
}
void consume() {
std::unique_lock<std::mutex> lgd(m_mc->mt);
while (m_que->empty()) {
int i = ;
m_mc->cv.wait(lgd);
}
m_que->pop();
std::cout << "Consume Thread consume " << std::endl;
}
void runConsume() {
while (!m_stop) {
std::this_thread::sleep_for(std::chrono::seconds());
consume();
}
}
void start() {
m_trd.reset(new std::thread(std::bind(std::mem_fun(&Consume::runConsume), this)));
}
void stop() {
m_stop = true;
} private:
std::queue<int> * m_que;
Mutex_Condition * m_mc;
std::shared_ptr<std::thread> m_trd;
volatile bool m_stop; };
二、生产者消费者-双缓冲
一个公共缓存区,由于多线程访问的锁冲突较大,可以采取双缓冲手段来解决锁的冲突
双缓冲的关键:双缓冲队列的数据交换
1)生产者线程不断的向生产者队列A写入数据,当队列中有数据时,进行数据的交换,交换开始启动时通过条件变量通知交换线程来处理最先的数据交换。
2)数据交换完成后,通过条件变量通知消费者处理数据,此时交换线程阻塞到消费者数据处理完成时通知的条件变量上。
3)消费者收到数据交换后的通知后,进行数据的处理,数据处理完成后,通知交换线程进行下一轮的双缓冲区的数据交换。
要点:
生产者除了在数据交换时,其余时刻都在不停的生产数据。
数据交换队列需要等待消费者处理数据完成的通知,以进行下一轮交换。
消费者处理数据时,不进行数据交换,生产者同时会不断的生产数据,消费者需要等待数据交换完成的通知,并且发送消费完成的通知给交换线程
使用条件变量的版本实现
typedef struct Mutex_Condition{
std::mutex mt;
std::condition_variable cv;
}Mutex_Condition; class Produce_1 {
public:
Produce_1(std::queue<int> * que_1, std::queue<int> * que_2, Mutex_Condition * mc_1 , Mutex_Condition * mc_2) {
m_read_que = que_1;
m_writer_que = que_2;
m_read_mc = mc_1;
m_writer_mc = mc_2;
m_stop = false; }
void runProduce() {
while (!m_stop) {
std::this_thread::sleep_for(std::chrono::microseconds( * ));
std::lock_guard<std::mutex> lgd(m_writer_mc->mt);
m_writer_que->push();
m_writer_mc->cv.notify_one();
std::cout << "m_writer push" << std::endl;
} }
void join() {
m_trd->join();
m_trd.reset();
}
void start() {
m_trd.reset(new std::thread(std::bind(std::mem_fun(&Produce_1::runProduce), this)));
}
void stop() {
m_stop = true;
}
private:
Mutex_Condition * m_read_mc;
Mutex_Condition * m_writer_mc;
std::queue<int> * m_read_que;
std::queue<int> * m_writer_que;
volatile bool m_stop;
std::shared_ptr<std::thread> m_trd;
}; class Consume_1 {
public:
Consume_1(std::queue<int> * que_1, std::queue<int> * que_2, Mutex_Condition * mc_1,Mutex_Condition * mc_2,Mutex_Condition * switch_mc) {
m_read_que = que_1;
m_writer_que = que_2;
m_read_mc = mc_1;
m_writer_mc = mc_2;
m_stop = false;
m_switch_mc = switch_mc;
} void runConsume() {
while (!m_stop) {
while (true) {
std::unique_lock<std::mutex> ulg(m_read_mc->mt);
while (m_read_que->empty()) {
m_read_mc->cv.wait(ulg);
}
//deal data
//std::lock_guard<std::mutex> ulg(m_read_mc->mt);
while (!m_read_que->empty()) {
m_read_que->pop();
std::cout << "m_read_queue pop" << std::endl;
}
m_switch_mc->cv.notify_one();
}
}
}
void join() {
m_trd->join();
m_trd.reset();
}
void start() {
m_trd.reset(new std::thread(std::bind(std::mem_fun(&Consume_1::runConsume), this)));
}
void stop() {
m_stop = true;
}
private:
Mutex_Condition * m_read_mc;
Mutex_Condition * m_writer_mc;
Mutex_Condition * m_switch_mc;
std::queue<int> * m_read_que;
std::queue<int> * m_writer_que;
volatile bool m_stop;
std::shared_ptr<std::thread> m_trd;
};
void que_switch_trd(std::queue<int> * read_que, std::queue<int> * writer_que, Mutex_Condition * read_mc, Mutex_Condition * writer_mc,Mutex_Condition * switch_mc) {
while (true) {
{
std::unique_lock<std::mutex> ulg(writer_mc->mt);
while (writer_que->empty()) {
writer_mc->cv.wait(ulg);
}
std::lock_guard<std::mutex> ulg_2(read_mc->mt);
std::swap(*read_que, *writer_que);
std::cout << "switch queue" << std::endl;
if (!read_que->empty()) {
read_mc->cv.notify_one();
}
}
std::unique_lock<std::mutex> ulg_2(switch_mc->mt);
while (!read_que->empty()) {
switch_mc->cv.wait(ulg_2);
}
}
}
int main(){ Mutex_Condition mc_1;
Mutex_Condition mc_2;
Mutex_Condition mc_3;
std::queue<int> que_1;
std::queue<int> que_2; Produce_1 produce_1(&que_1, &que_2, &mc_1, &mc_2);
Consume_1 consume_1(&que_1, &que_2, &mc_1, &mc_2,&mc_3); std::thread trd(std::bind(&que_switch_trd, &que_1, &que_2, &mc_1, &mc_2,&mc_3));
produce_1.start();
consume_1.start(); produce_1.join();
consume_1.join();
trd.join(); return ;
}
使用互斥锁的实现
#include<mutex>
#include<thread>
#include<queue>
#include<iostream>
#include<chrono> class DBQueue{
public:
void push(int i_) {
std::lock_guard<std::mutex> lock(m_mt);
std::cout << "write_que push " << i_ << std::endl;
m_write_que.push(i_);
}
void swap(std::queue<int> & read_que) {
std::lock_guard<std::mutex> lock(m_mt);
std::swap(m_write_que,read_que);
std::cout << "switch swap" << std::endl;
}
private:
std::queue<int> m_write_que;
std::mutex m_mt;
};
void produce(DBQueue * que) {
while (true) {
std::this_thread::sleep_for(std::chrono::microseconds(*));
que->push();
}
}
void consume(DBQueue * que) {
std::queue<int> read_que;
while (true) {
std::this_thread::sleep_for(std::chrono::microseconds(*));
if (read_que.empty()) {
que->swap(read_que);
//xxoo
while (!read_que.empty()) {
std::cout << "read_que pop" << std::endl;
read_que.pop();
}
}
}
}
int main()
{
DBQueue que;
std::thread trd_1(std::bind(&produce, &que));
std::thread trd_2(std::bind(&consume, &que));
trd_1.join();
trd_2.join();
return ;
}
两个版本的区别 sleep的区别,sleep处理的时效性较差,不加sleep,cpu占用率又比较高,所以条件变量是比较好的选择。
C++11 实现生产者消费者双缓冲的更多相关文章
- C++11实现生产者消费者问题
生产者消费者问题是多线程并发中一个非常经典的问题.我在这里实现了一个基于C++11的,单生产者单消费者的版本,供大家参考. #include <windows.h> #include &l ...
- C++11 实现生产者消费者模式
代码都类似,看懂一个,基本都能理解了. 共有代码: #include <cstdlib>#include <condition_variable>#include <io ...
- C++11 并发指南九(综合运用: C++11 多线程下生产者消费者模型详解)
前面八章介绍了 C++11 并发编程的基础(抱歉哈,第五章-第八章还在草稿中),本文将综合运用 C++11 中的新的基础设施(主要是多线程.锁.条件变量)来阐述一个经典问题——生产者消费者模型,并给出 ...
- [OS] 生产者-消费者问题(有限缓冲问题)
·最简单的情形--(一个生产者 + 一个消费者 + 一个大小为1的有限缓冲) 首先来分析其中的同步关系: ·必须在生产者放入一个产品之后,消费者才能够从缓冲中取出产品来消费.·只有在消费者从缓冲区中取 ...
- 综合运用: 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实现) 再谈多线程模型之生产者消费 ...
随机推荐
- 如何在Windows环境下安装Linux系统虚拟机
如何在Windows环境下安装Linux系统虚拟机 本篇经验写给想要入门学习C语言的小白们.Windows系统因为使用窗口图形化,操作简单,功能多样,所以我们在Windows环境下可以做到很多,但想要 ...
- 在改变某一项目的svn的地址,relocate
不要忘记删除原有.svn文件.
- Android-Camera+SurfaceView
Camera相机是属于硬件,每台设备的Camera硬件配置的参数都是不一样的,Camera通常是用来拍照,扫描二维码等等 AndroidManifest.xml配置Camera需要的权限: <! ...
- Mac提示App已损坏 你应该将它移到废纸篓的解决方案
现象 "Elmedia Player.app"已损坏,打不开. 您应该将它移到废纸篓. 原因 很多朋友们在安装软件时Mac OS系统出现提示"XXXApp 已损坏&quo ...
- oracle 批量删除触发器
--生成删除触发器的语句 select 'drop trigger "'||trigger_name||'";' from all_triggers where TRIGGER_ ...
- 在 Docker 中部署 ASP.NET CORE 应用
有了 Docker 之后, 部署起来却这间非常方便,环境不用搭了, 直接创建一个 microsoft/aspnetcore 的容器, 在本地开发好后, 把内容直接部署到容器中. 下面的命令是把本地发布 ...
- you need to be root to perform this command
在linux 终端执行某条命令时 提示一下错误 you need to be root to perform this command 是提示要获取root权限 输入su 回车输入密码 即可解决 参考 ...
- 初学Ionic
官网 https://ionicframework.com/ 如连接所示,可跳转到该前端框架的官网,在这里提供了两种方式可供大家学习: Code with the CLI Design with lo ...
- sharepoint 2016 download
链接: http://pan.baidu.com/s/1pLBwvnt 密码: c928 SharePoint 2016 Server中文版,
- windows下简单验证码识别——完美验证码识别系统
此文已由作者徐迪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 讲到验证码识别,大家第一个可能想到tesseract.诚然,对于OCR而言,tesseract确实很强大,自带 ...