基础的生产者消费者模型,生产者向公共缓存区写入数据,消费者从公共缓存区读取数据进行处理,两个线程访问公共资源,加锁实现数据的一致性。

通过加锁来实现

 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 实现生产者消费者双缓冲的更多相关文章

  1. C++11实现生产者消费者问题

    生产者消费者问题是多线程并发中一个非常经典的问题.我在这里实现了一个基于C++11的,单生产者单消费者的版本,供大家参考. #include <windows.h> #include &l ...

  2. C++11 实现生产者消费者模式

    代码都类似,看懂一个,基本都能理解了. 共有代码: #include <cstdlib>#include <condition_variable>#include <io ...

  3. C++11 并发指南九(综合运用: C++11 多线程下生产者消费者模型详解)

    前面八章介绍了 C++11 并发编程的基础(抱歉哈,第五章-第八章还在草稿中),本文将综合运用 C++11 中的新的基础设施(主要是多线程.锁.条件变量)来阐述一个经典问题——生产者消费者模型,并给出 ...

  4. [OS] 生产者-消费者问题(有限缓冲问题)

    ·最简单的情形--(一个生产者 + 一个消费者 + 一个大小为1的有限缓冲) 首先来分析其中的同步关系: ·必须在生产者放入一个产品之后,消费者才能够从缓冲中取出产品来消费.·只有在消费者从缓冲区中取 ...

  5. 综合运用: C++11 多线程下生产者消费者模型详解(转)

    生产者消费者问题是多线程并发中一个非常经典的问题,相信学过操作系统课程的同学都清楚这个问题的根源.本文将就四种情况分析并介绍生产者和消费者问题,它们分别是:单生产者-单消费者模型,单生产者-多消费者模 ...

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

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

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

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

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

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

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

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

随机推荐

  1. 如何在Windows环境下安装Linux系统虚拟机

    如何在Windows环境下安装Linux系统虚拟机 本篇经验写给想要入门学习C语言的小白们.Windows系统因为使用窗口图形化,操作简单,功能多样,所以我们在Windows环境下可以做到很多,但想要 ...

  2. 在改变某一项目的svn的地址,relocate

    不要忘记删除原有.svn文件.

  3. Android-Camera+SurfaceView

    Camera相机是属于硬件,每台设备的Camera硬件配置的参数都是不一样的,Camera通常是用来拍照,扫描二维码等等 AndroidManifest.xml配置Camera需要的权限: <! ...

  4. Mac提示App已损坏 你应该将它移到废纸篓的解决方案

    现象 "Elmedia Player.app"已损坏,打不开. 您应该将它移到废纸篓. 原因 很多朋友们在安装软件时Mac OS系统出现提示"XXXApp 已损坏&quo ...

  5. oracle 批量删除触发器

    --生成删除触发器的语句 select 'drop trigger "'||trigger_name||'";' from all_triggers  where TRIGGER_ ...

  6. 在 Docker 中部署 ASP.NET CORE 应用

    有了 Docker 之后, 部署起来却这间非常方便,环境不用搭了, 直接创建一个 microsoft/aspnetcore 的容器, 在本地开发好后, 把内容直接部署到容器中. 下面的命令是把本地发布 ...

  7. you need to be root to perform this command

    在linux 终端执行某条命令时 提示一下错误 you need to be root to perform this command 是提示要获取root权限 输入su 回车输入密码 即可解决 参考 ...

  8. 初学Ionic

    官网 https://ionicframework.com/ 如连接所示,可跳转到该前端框架的官网,在这里提供了两种方式可供大家学习: Code with the CLI Design with lo ...

  9. sharepoint 2016 download

     链接: http://pan.baidu.com/s/1pLBwvnt 密码: c928 SharePoint 2016 Server中文版,

  10. windows下简单验证码识别——完美验证码识别系统

    此文已由作者徐迪授权网易云社区发布. 欢迎访问网易云社区,了解更多网易技术产品运营经验. 讲到验证码识别,大家第一个可能想到tesseract.诚然,对于OCR而言,tesseract确实很强大,自带 ...