Day4
本章对生产者--消费者模型进行学习,此模型在程序设计中应用非常广泛,并且我们的webserver项目的线程池、sql数据库连接池就是基于生产者--消费者模型来实现的。
什么是生产者消费者模型
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个阻塞队列就是用来给生产者和消费者解耦的。
基于BlockingQueue的生产者消费者模型
单生产者单消费者模型
Makefile的编写:
main:main.cc
g++ $^ -o $@ -lpthread
.PHONY:clean
clean:
rm -f main
BlockQueue.hpp
#ifndef __BLOCK_QUEUE_H__
#define __BLOCK_QUEUE_H__
#include<iostream>
#include<queue>
#include<pthread.h>
#include<unistd.h>
class BlockQueue
{
private:
std::queue<int> q;
size_t _cap;
pthread_mutex_t lock;
pthread_cond_t c_cond;//消费者的条件不满足时,将来消费者在该条件变量下等
pthread_cond_t p_cond;//生产者的条件不满足时,将来生产者在该条件下等
public:
bool IsFull()
{
return q.size() >= _cap;
}
bool IsEmpty()
{
return q.empty();
}
void LockQueue()
{
pthread_mutex_lock(&lock);
}
void UnLockQueue()
{
pthread_mutex_unlock(&lock);
}
void WakeUpComsumer()
{
pthread_cond_signal(&c_cond);
}
void WakeUpProductor()
{
pthread_cond_signal(&p_cond);
}
void ProducterWait()
{
pthread_cond_wait(&p_cond,&lock);
//这里为什么要传锁,我们在等待时肯定是条件不满足了,我们通过判断才知道条件满不满足,
//判断就需要保证进入临界区,我们是持有锁进入的,wait的时候必须要释放锁
//在调用该函数的时候,自动会释放lock
//当该函数被返回时,返回到了临界区内,所以,该函数会让该线程重新持有该锁
}
void ComsumerWait()
{
pthread_cond_wait(&c_cond,&lock);//在消费者释放锁时,生产者正申请锁,而消费者在等待
}
public:
BlockQueue(size_t cap):_cap(cap)
{
pthread_mutex_init(&lock,nullptr);
pthread_cond_init(&c_cond,nullptr);
pthread_cond_init(&p_cond,nullptr);
}
void Put(int in)
{
LockQueue();
//if(isFull())
while(isFull())
{
WakeUpComsumor();//唤醒消费者
ProducterWait();//生产者等待
}
q.push(in);
UnLockQueue();
}
void Get(int& out)
{
LockQueue();
//if(IsEmpty)
while(IsEmpty())
{
WakeUpProductor();
ComsumerWait();//消费者者等待
}
out = q.front();
q.pop();
LockQueue();
}
~BlockQueue()
{
pthread_cond_destroy(&lcok);
pthread_cond_destroy(&c_cond);
pthread_cond_destroy(&p_cond);
}
};
#endif
main.cc
#include"BlockQueue.hpp"
using namespace std;
void* consumer_run(void* arg)
{
BlockQueue *bq = (BlockQueue*)arg;
while(true)
{
int n = 0;
bq->Get(n);
cout<<"consumer data is : " << n <<endl;
}
}
void* productor_run(void* arg)
{
BlockQueue *bq = (BlockQueue*)arg;
while(true)
{
int data = rand()%10+1;
bq->Put(data);
cout<<"product data is : "<<data<<endl;
}
}
int main()
{
BlockQueue *bq = new BlockQueue(5);
pthread_t c,p;
pthread_create(&c,nullptr,consumer_run,(void*)bq);
pthread_create(&p,nullptr,productor_run,(void*)bq);
pthread_join(c,nullptr);
pthread_join(p,nullptr);
delete bq;
return 0;
}
多生产者多消费者模型
上面是单生产者单消费者模型,只解决了生产者和消费者之间的关系,如果是多生产者多消费者模型那么需要添加另外两种关系:还有生产者和生产者的关系(互斥),以及消费者和消费者的关系(互斥)所以我们只需要在外面生产者和消费者的例程中放数据和取数据加锁即可:
#include"BlockQueue.hpp"
using namespace std;
pthread_mutex_t c_lock;
pthread_mutex_t p_lock;
void* consumer_run(void* arg)
{
BlockQueue *bq = (BlockQueue*)arg;
while(true)
{
int n = 0;
pthread_mutex_lock(&c_lock);
bq->Get(n);
pthread_mutex_unlock(&c_lock);
cout<<"consumer data is : " << n <<endl;
}
}
void* productor_run(void* arg)
{
BlockQueue *bq = (BlockQueue*)arg;
while(true)
{
pthread_mutex_lock(&p_lock);
int data = rand()%10+1;
bq->Put(data);
pthread_mutex_unlock(&p_lock);
cout<<"product data is : "<<data<<endl;
}
}
int main()
{
BlockQueue *bq = new BlockQueue(5);
pthread_t c,p;
pthread_mutex_init(&c_lock,nullptr);
pthread_mutex_init(&p_lock,nullptr);
pthread_create(&c,nullptr,consumer_run,(void*)bq);
pthread_create(&c,nullptr,consumer_run,(void*)bq);
pthread_create(&c,nullptr,consumer_run,(void*)bq);
pthread_create(&c,nullptr,consumer_run,(void*)bq);
pthread_create(&p,nullptr,productor_run,(void*)bq);
pthread_create(&p,nullptr,productor_run,(void*)bq);
pthread_create(&p,nullptr,productor_run,(void*)bq);
pthread_create(&p,nullptr,productor_run,(void*)bq);
pthread_create(&p,nullptr,productor_run,(void*)bq);
pthread_join(c,nullptr);
pthread_join(p,nullptr);
delete(bq);
pthread_mutex_destroy(&c_lock);
pthread_mutex_destroy(&p_lock);
return 0;
}