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

通过加锁来实现

 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. Java® Language Specification

    Java™ Platform, Standard Edition 8 API Specification http://docs.oracle.com/javase/8/docs/api/ The J ...

  2. 20145233计算机病毒实践九之IDA的使用

    20145233计算机病毒实践之IDA的使用 PSLIST导出函数做了什么 这个函数是一个export函数,所以在view中选择export 查到后,双击打开这个函数的位置 仔细看这个函数可以发现这个 ...

  3. oracle 批量删除触发器

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

  4. Jenkins 集成 git .net 和nuget

    1. 源码配置 在 Credentials中配置 git 账号密码(如果是Gitee  可以使用 Jenkins Gitee Plugin) 2. 构建编译版本 2.1 批处理的目的 还原Nuget包 ...

  5. Docker 入门笔记

    Docker 可以理解为一个轻量化的虚拟机, 启动速度快,本身占的资源小 [重要], 容器里是不能保存数据的,容器只要一停止, 所有的数据都会丢失,所以如果重要的数据, 都需要通过配制,把数据保存在 ...

  6. DNS本机可解析,其他主机通过本机无法解析问题

    新建了一个redhat虚拟机,将此虚拟机作为dns服务器使用,配置完以后宿主机的dns服务器设置为配置好的虚拟机地址,结果总是显示no Server Reached,没有服务器可以到达,花了很长时间终 ...

  7. SQLServer数据库的状态一直都是正在还原

    解决方案: 执行以下SQL语句 restore database [数据库名称] with recovery

  8. leetcode 回文数

    判断一个整数是否是回文数.回文数是指正序(从左向右)和倒序(从右向左)读都是一样的整数. 示例 1: 输入: 121 输出: true 示例 2: 输入: -121 输出: false 解释: 从左向 ...

  9. Visual Studio 2013的新特性介绍

    cnbeta新闻:微软正式发布Visual Studio 2013 RTM版,微软还发布了Visual Studio 2013的最终版本..NET 4.5.1以及Team Foundation Ser ...

  10. django系列8.3.2--django中间件实现登录验证(2) 个人构想逻辑

    middleware.py from django.utils.deprecation import MiddlewareMixin from django.shortcuts import rend ...