三 Linux--多线程

生产者消费者模型【三 Linux--多线程】概念: 生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题 。生产者和消费者彼此之间不直接通讯,而通过一个来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里?。枞恿芯拖嗟庇谝桓龌撼迩?,平衡了生产者和消费者的处理能力 。这个阻塞队列就是用来给生产者和消费者解耦的 。
生产消费者模型优点:

  • 解耦:生产者和消费者是通过一个共享数据区域来进行通信 。而不是直接进行通信,这样两个角色之间的依耐性就降低了(代码层面实现解耦),变成了角色与共享数据区域之间的弱耦合,一个逻辑出错不影响两一个逻辑,二者变得更独立 。
  • 支持并发:生产者负责生产数据,消费者负责拿数据 。生产者生产完数据可以继续生产,大部分时间内是不需要等待消费者消费数据才继续生产 。也就是说,在任一时刻,二者都是在正常处理任务的,进度都得以推进 。
  • 支持忙闲下不均:生产者生产了数据是放进容器中 , 消费者不必立即消费,可以慢慢地从容器中取数据 。容器快要空了,消费者的消费速度就可以降下来,让生产者继续生产 。
生产消费模型特征(简记321):
  1. 3种关系: 生产者与生产者(互斥)、生产者与消费者(同步(主要)和互斥)和消费者与消费者(互斥)
  2. 两个角色: 生产者和消费者
  3. 一个交易场所: 容器、共享资源等

三 Linux--多线程

文章插图
基于阻塞队列的生产者消费者模型阻塞队列的特点:
  • 当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素
  • 当队列满时,往队列里存放元素的操作也会被阻塞,直到有元素被从队列中取出(以上的操作都是基于不同的线程来说的,线程在对阻塞队列进程操作时会被阻塞)
  • 在这个模型中,生产者和消费者的交易场所就是阻塞队列
实现概述:因为交易场所是一个阻塞队列 , 所以,我封装了一个BlcokingQueue 的类,这里提供了放数据和取数据这样两个主要的方法 。其中,有五个成员变量:
  • 队列: 使用STL中的queue来实现
  • 容量: 阻塞队列的容量,由用户给定 , 我们也可以提供一个默认的容量
  • 互斥量: 为了实现生产者和消费者的同步,我们需要使用条件变量和互斥量来实现同步的操作
  • 生产者唤醒和等待的条件变量: 当队列满了,生产者等待条件满足 , 应该挂起等待,等待消费者唤醒
  • 消费者唤醒和等待的条件变量: 当队列为空,消费者等待条件满足,应该挂起等待,等待生产者唤醒
构造函数和析构函数:
  • 构造函数做初始化和资源分配的操作,分配锁资源和条件变量
  • 析构函数做清理资源的操作,对锁和条件变量进行销毁
队列类的整体架构#include<iostream>#include<string.h>using namespace std;//标准命名空间//类模板template<class T>class BlockQueue{public://构造函数,化容量为5BlockQueue(int capacity = 5):_capacity(capacity){//初始化锁和互斥量pthread_mutex_init(&_lock,nullptr);pthread_cond_init(&_c_cond,nullptr);pthread_cond_init(&_p_cond,nullptr);}//析构函数~BlockQueue(){pthread_mutex_destroy(&_lock);pthread_cond_destroy(&_c_cond);pthread_cond_destroy(&_p_cond);}private://队列容器queue<T> _q;size_t_capacity;//队列最大容器pthread_mutex_t _lock;//互斥锁pthread_cond_t _c_cond;//消费者被唤醒和挂起的条件变量pthread_cond_t _p_cond;//生产者被唤醒和挂起的条件变量}基本方法的封装我对阻塞队列的一些基本操作进行了封装,有以下几个处理动作(可以设置为私有方法):
  • 判断队列为空或为满
  • 唤醒生产者和唤醒消费者
  • 生产者挂起等待和消费者挂起等待
  • 加锁和解锁
private:bool IsFull(){return _q.size() == _capacity;}bool IsEmpty(){return _q.empty();}void ConsumerWait(){cout << "consumer wait...." << endl;pthread_cond_wait(&_c_cond, &_lock);}void WakeUpConsumer(){cout << "wake up consumer...." << endl;pthread_cond_broadcast(&_c_cond);}void ProductorWait(){cout << "productor wait...." << endl;pthread_cond_wait(&_p_cond, &_lock);}void WakeUpProductor(){cout << "wake up productor...." << endl;pthread_cond_broadcast(&_p_cond);}void LockQueue(){pthread_mutex_lock(&_lock);}void UnLockQueue(){pthread_mutex_unlock(&_lock);}

推荐阅读