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

通过加锁来实现

 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. String 、 StringBuffer 和 StringBuilder

    StringBuffer (一个线程安全的可变字符串序列,用于多线程) A thread-safe, mutable sequence of characters. StringBuilder (可变 ...

  2. xib下这种方式创建cell

      这种方法在iOS5.0之前是不能够创建成功的.   MEConvertListTableViewCell *cell = [tableView dequeueReusableCellWithIde ...

  3. c+内存管理机制

    内存管理是C++最令人切齿痛恨的问题,也是C++最有争议的问题,C++高手从中获得了更好的性能,更大的自由,C++菜鸟的收获则是一遍一遍的 检查代码和对C++的痛恨,但内存管理在C++中无处不在,内存 ...

  4. 个人作业代码GitHub提交步骤

    代码提交地址: https://github.com/eudaem/homework1 步骤: 1)用个人账号登陆GitHub,并访问代码提交地址页面,点击页面右上角的“Fork”按钮,拷贝homew ...

  5. POJ1273&&Hdu1532 Drainage Ditches(最大流dinic) 2017-02-11 16:28 54人阅读 评论(0) 收藏

    Drainage Ditches Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others) ...

  6. 23 DesignPatterns学习笔记:C++语言实现 --- 1.3 Singletion

    23 DesignPatterns学习笔记:C++语言实现 --- 1.3 Singletion 2016-07-21 (www.cnblogs.com/icmzn) 模式理解  

  7. PHP全栈学习笔记19

    thinkphp框架是一个免费的,开源,快速,简单的面向对象的轻量级PHP开发框架. 了解什么是thinkphp概述,thinkphp项目目录结构,thinkphp的控制器,视图,thinkphp项目 ...

  8. wp调用百度服务api

    通过百度开放平台申请api成功后,百度会提供一个application key简称ak和一个security key简称sk. 看一下某个服务url的格式 1. url前缀 2. 服务类型 3. 参数 ...

  9. asp.net——XML格式导出Excel

    下面介绍一种导出Excel的方法: 此方法不需要在服务器上安装Excel,采用生成xml以excel方式输出到客户端,可能需要客户机安装excel,所以也不会有乱七八糟的权限设定,和莫名其妙的版本问题 ...

  10. eFrameWork学习笔记-eList

    HTML: <div style="margin:8px;"> <h1>.不分页</h1> <asp:Repeater id=" ...