Linux生产者与消费者模型
文章目录
什么是生产者与消费者模型
生产者消费者模型就是通过一个容器来解决生产者和消费者的强耦合问题
。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的
。
生产者与消费者其实在我们生活中很常见,比如工厂生产商品,我们购买商品,那么这里工厂就是生产者,我们就是消费者。还有一个仓库,当生产者生产出货物,将货物放入仓库,我们消费时货物从仓库发出。这三者共同组成生产者和消费者模型。
生产者消费者模型特点
- 三种关系:
生产者和生产者
之间的互斥关系
,消费者和消费者
之间的互斥关系
,生产者和消费者之间
的同步关系
- 两个角色:生产者和消费者(通常是两个线程)
- 一个交易场所:指这个模型里的仓库,也就是内存里的
一块缓冲区
生产者与消费者模型的优点
- 解耦
有了缓冲区之后,生产者和消费者之间不会直接通信,依赖关系将大大减少,如果其中一方出现问题,不会对另一方产生很大影响
- 支持并发
如果没有这个“仓库”,那么生产者和消费者之间是串行执行的,一方生产一个,一方消费一个,如果一方出现问题或者阻塞,那么整个程序都会阻塞,效率就会降低,而有了这个缓冲区,生产者只管生产,消费者只需从仓库内消费,两个线程同时操作,互不影响,效率提高
- 支持忙闲不均
如果生产者生产的速度不均衡,导致时快时慢,让消费者来不及消费,那么缓冲区的作用就体现出来了,让消费者来不及处理的数据先放在缓冲区中,等消费者有时间再去处理。减少忙的时间太忙,闲的时间太闲的现象。
基于阻塞队列(BlockingQueue)的生产者消费者模型
阻塞队列(BlockingQueue)
在多线程编程中阻塞队列(Blocking Queue)是一种常用于实现生产者和消费者模型的数据结构
。其与普通的队列区别在于,当队列为空时,从队列获取元素的操作将会被阻塞,直到队列中被放入了元素;当队列满时,往队列里存放元素的操作也会被阻塞,直到有元素被从队列中取出
(以上的操作都是基于不同的线程来说的,线程在对阻塞队列进程操作时会被阻塞)
这个阻塞队列就是模型里"仓库"的具体实现,这个"仓库"也可以是别的数据结构
用 C++ queue 模拟阻塞队列的生产消费模型
单生产者单消费者
代码实现:
- makeflie
main:main.cpp
g++ -o $@ $^ -std=c++11 -lpthread
.PHONY:clean
clean:
rm -f main
- BlockQueue.hpp
#ifndef __QUEUE_BLOCK_H__
#define __QUEUE_BLOCK_H__
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<queue>
template<class T>
class BlockQueue {
public:
BlockQueue(size_t capacity) :_capacity(capacity) {
pthread_mutex_init(&lock, nullptr);
pthread_cond_init(&p_cond, nullptr);
pthread_cond_init(&c_cond, nullptr);
}
public:
void WakeUpConsumer() {
pthread_cond_signal(&c_cond);
std::cout << "wake up Consumer" << std::endl;
}
void WakeUpProductor() {
pthread_cond_signal(&p_cond);
std::cout << "wake up productor" << std::endl;
}
void ProductorWait() {
pthread_cond_wait(&p_cond, &lock);
std::cout << "productor wait" << std::endl;
}
void ConsumerWait() {
pthread_cond_wait(&c_cond, &lock);
std::cout << "consumer wait" << std::endl;
}
void LockQueue() {
pthread_mutex_lock(&lock);
}
void UnLockQueue() {
pthread_mutex_unlock(&lock);
}
void put(const T& t) {
LockQueue();
while (IsFull()) {
WakeUpConsumer();
ProductorWait();
}
_q.push(t);
UnLockQueue();
}
void take(T& t) {
LockQueue();
while (IsEmpty()) {
WakeUpProductor();
ConsumerWait();
}
t = _q.front();
_q.pop();
UnLockQueue();
}
bool IsFull() {
return _q.size() >= _capacity;
}
bool IsEmpty() {
return _q.empty();
}
~BlockQueue() {
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&c_cond);
pthread_cond_destroy(&p_cond);
}
private:
std::queue<T> _q;
size_t _capacity;
pthread_mutex_t lock;
pthread_cond_t p_cond;
pthread_cond_t c_cond;
};
#endif
- main.cpp
#include"BlockQueue.hpp"
using namespace std;
void* Productor_run(void* arg){
sleep(1);
BlockQueue<int>* pbq=(BlockQueue<int>*)arg;
int t=0;
while(true){
t++;
pbq->put(t);
sleep(1);
cout<<"Productor put data:"<<t<<endl;
}
}
void* Consumer_run(void* arg){
BlockQueue<int>* pbq=(BlockQueue<int>*)arg;
while(true){
int t=0;
pbq->take(t);
sleep(1);
cout<<"Consumer take data:"<<t<<endl;
}
}
int main(){
BlockQueue<int> bq(5);
pthread_t p,c;
pthread_create(&p,nullptr,Productor_run,(void*)&bq);
pthread_create(&c,nullptr,Consumer_run,(void*)&bq);
pthread_join(p,nullptr);
pthread_join(c,nullptr);
return 0;
}
多消费者,多生产者,生产和消费任务 Task
前面是一个生产者一个消费者,两者之间是同步关系,那么增加了消费者和生产者,就要维护生产者和消费者之间的互斥关系
- BlockQueue.hpp
#ifndef __QUEUE_BLOCK_H__
#define __QUEUE_BLOCK_H__
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<queue>
//任务封装
class Task {
public:
int _x;
int _y;
public:
Task() {}
Task(int x, int y) :_x(x), _y(y)
{}
int run() {
return _x + _y;
}
};
template<class T>
class BlockQueue {
private:
std::queue<T> _q;
size_t _capacity;
pthread_mutex_t lock;
pthread_cond_t p_cond;
pthread_cond_t c_cond;
public:
BlockQueue(size_t capacity) :_capacity(capacity) {
pthread_mutex_init(&lock, nullptr);
pthread_cond_init(&p_cond, nullptr);
pthread_cond_init(&c_cond, nullptr);
}
private:
void WakeUpConsumer() {
pthread_cond_signal(&c_cond);
std::cout << "wake up Consumer" << std::endl;
}
void WakeUpProductor() {
pthread_cond_signal(&p_cond);
std::cout << "wake up productor" << std::endl;
}
void ProductorWait() {
pthread_cond_wait(&p_cond, &lock);
std::cout << "productor wait" << std::endl;
}
void ConsumerWait() {
pthread_cond_wait(&c_cond, &lock);
std::cout << "consumer wait" << std::endl;
}
void LockQueue() {
pthread_mutex_lock(&lock);
}
void UnLockQueue() {
pthread_mutex_unlock(&lock);
}
bool IsFull() {
return _q.size() >= _capacity;
}
bool IsEmpty() {
return _q.empty();
}
public:
void Put(const T& t) {
//维护生产者和消费者间的互斥关系
LockQueue();
while (IsFull()) {
WakeUpConsumer();
ProductorWait();
}
_q.push(t);
UnLockQueue();
}
void Take(T& t) {
//维护生产者和消费者间的互斥关系
LockQueue();
while (IsEmpty()) {
WakeUpProductor();
ConsumerWait();
}
t = _q.front();
_q.pop();
UnLockQueue();
}
~BlockQueue() {
pthread_mutex_destroy(&lock);
pthread_cond_destroy(&c_cond);
pthread_cond_destroy(&p_cond);
}
};
#endif
- main.cpp
#include"BlockQueue.hpp"
using namespace std;
//两个角色用两把锁
pthread_mutex_t p_lock;
pthread_mutex_t c_lock;
void* Productor_run(void* arg){
sleep(1);
BlockQueue<Task>* pbq=(BlockQueue<Task>*)arg;
while(true){
//维护多个生产者之间的互斥关系
pthread_mutex_lock(&p_lock);
int x = rand()%10+1;
int y = rand()%100+1;
Task t(x,y);
pbq->Put(t);
cout<<"Producter id:"<<pthread_self()<<" "<<"Producter Task is "<<x<<"+"<<y<<"=?"<<endl;
pthread_mutex_unlock(&p_lock);
sleep(1);
}
}
void* Consumer_run(void* arg){
BlockQueue<Task>* pbq=(BlockQueue<Task>*)arg;
while(true){
//维护多个消费者之间的互斥关系
pthread_mutex_lock(&c_lock);
Task t;
pbq->Take(t);
cout<<"Consumer id:"<<pthread_self()<<" "<<"Consumer Task is:"<<t._x<<"+"<<t._y<<"="<<t.run()<<endl;
pthread_mutex_unlock(&c_lock);
sleep(1);
}
}
int main(){
BlockQueue<Task> bq(5);
pthread_t p1,p2,p3,c1,c2,c3;
pthread_create(&p1,nullptr,Productor_run,(void*)&bq);
pthread_create(&p2,nullptr,Productor_run,(void*)&bq);
pthread_create(&p3,nullptr,Productor_run,(void*)&bq);
pthread_create(&c1,nullptr,Consumer_run,(void*)&bq);
pthread_create(&c2,nullptr,Consumer_run,(void*)&bq);
pthread_create(&c3,nullptr,Consumer_run,(void*)&bq);
pthread_join(p1,nullptr);
pthread_join(p2,nullptr);
pthread_join(p3,nullptr);
pthread_join(c1,nullptr);
pthread_join(c2,nullptr);
pthread_join(c3,nullptr);
pthread_mutex_destroy(&c_lock);
pthread_mutex_destroy(&p_lock);
return 0;
}
也就是说,这个模型下,要让生产者和消费者处理任务时,只需提供对应的Task类,类中实现数据的处理方法即可