一、前言
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。
生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
要实现生产者消费者模式。首先要保证:
三个关系:生产者和生产者(竞争关系,互斥关系)、消费者和消费者(竞争关系,互斥关系)、生产者和消费者(竞争关系(保证数据的正确性),同步关系(保证多线程协调))。
两种角色:生产者和消费者(特定的进程或线程)。
一个交易场所:通常指内存的一段缓冲区。
生产者消费者模型优点
- 解耦
- 支持并发
- 支持忙闲不均
二、基于BlockingQueue的生产者消费者模型
在多线程编程中阻塞队列(Blocking Queue)是一种常用于实现生产者和消费者模型的数据结构。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素;当队列满时,往队列里存放元素的操作也会被阻塞,直到有元素被从队列中取出(以上的操作都是基于不同的线程来说的,线程在对阻塞队列进程操作时会被阻塞)。
三、C++ queue模拟阻塞队列的生产消费模型
- 为了便于理解,以单生产者,单消费者,来进行讲解。
ProCon1.hpp
#include <iostream> #include <queue> #include <pthread.h> #include <unistd.h> #include <cstdlib> #include <ctime> #define NUM 6 template <class T> class PC { public: PC(int cap = NUM) : _cap(cap) { // 初始化锁和条件变量 pthread_mutex_init(&lock, nullptr); pthread_cond_init(&_empty, nullptr); pthread_cond_init(&_full, nullptr); } void Push(const T &in) { // 先申请锁 pthread_mutex_lock(&lock); // 判断是否为满 while (full()) { // 如果是满了,那么就必须等待,并把锁释放出去 pthread_cond_wait(&_full, &lock); } // 插入数据 q.push(in); // 队列中已经有数据了,唤醒正在等待的消费者。 if (q.size() >= _cap / 2) { pthread_cond_signal(&_empty); std::cout << "消费者快来消费吧 "; } // 释放锁