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

通过加锁来实现

 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. lnmp 一键安装包 nginx配置tp5 phpinfo模式 隐藏index.php

    tp5 url 线上访问 在nginx 上 出现404错误 那是因为pathinfo没有被支持 修改如下:找到   /usr/local/nginx/config/vhost/项目名.config s ...

  2. Jdom的简单操作

    http://blog.csdn.net/heirenheiren/article/details/7354108 http://www.cnblogs.com/hoojo/archive/2011/ ...

  3. mongo find

    MongoVUE 对应成语句,结构如下: db.logs.find({ "message" : /消息/ }, { "message" : 1 }).limit ...

  4. sockaddr与sockaddr_in

    struct sockaddr { unsigned short sa_family;     char sa_data[14]; }; 此数据结构用做bind.connect.recvfrom.se ...

  5. OpenGl中的Nurbs B样条曲面的封装的GLU的NURBS的接口

    OpenGl中的Nurbs B样条曲面的封装的GLU的NURBS的接口 创建一个NURBS对象: GLUnurbs* gluNewNurbsRenderer (void); //创建一个NURBS对象 ...

  6. Java异常封装

    转载: Java异常封装 Java里面的异常在真正工作中使用还是十分普遍的.什么时候该抛出什么异常,这个是必须知道的. 当然真正工作里面主动抛出的异常都是经过分装过的,自己可以定义错误码和异常描述. ...

  7. Template Method Design Pattern in Java

    Template Method is a behavioral design pattern and it’s used to create a method stub and deferring s ...

  8. 如何搭建eclipse+maven环境

    Maven这个个项目管理和构建自动化工具,越来越多的开发人员使用它来管理项目中的jar包.本文仅对Eclipse中如何安装.配置和使用Maven进行了介绍.完全step by step. 如果觉得本文 ...

  9. VR与AR的发展趋势分析

    概要 你是否想象过与神秘的深海生物近距离接触?你是否梦想过穿戴钢铁侠那样的超先进科技装备成为超级英雄?你又是否幻想过与梦中的女神面对面的交流?这些可能在以前都只能是存在于脑海中的幻想,可是在如今有一项 ...

  10. can not update ICEAuthority file mint或则ubuntu

    引起的原因为:设置了用户自动登录引起的. 1)去除自动登录 2)删除 ICEAuthority文件. 即可.