目录
1 模型简介
以现实中的生产消费为例。工厂作为生产者生产的产品被批发到商场,普通民众作为消费者到商场购买产品。在这之间生产者与消费者并不需要交互,而是通过商场这一个媒介完成整个生产消费的过程。
那么在我们的程序中也可以应用这个模型,一个线程产生数据作为生产者,一个线程处理数据作为消费者,中间使用阻塞队列来作为缓冲区。这样做的好处就是将生产和消费的行为分离,消费者不需要重复等待着生产者生产。提高了线程执行的效率。
2 基于BlockingQueue的生产者消费者模型
使用队列作为缓冲区的数据结构。在队列为空时,我们认为当前没有产品被生产,无法进行消费需要等待生产者生产;在队列为满时,我们认为。当前仓库已满,生产者不能再生产了,需要等待消费者消费。
代码实现
#pragma once
#include <iostream>
#include <queue>
#include <pthread.h>
namespace ns_blockqueue
{
const int default_cap = 5;
template<class T>
class BlockQueue
{
public:
BlockQueue(int cap = default_cap):_cap(cap)
{
pthread_mutex_init(&_mtx,nullptr);
pthread_cond_init(&_isfull,nullptr);
pthread_cond_init(&_isempty,nullptr);
}
~BlockQueue()
{
pthread_mutex_destroy(&_mtx);
pthread_cond_destroy(&_isfull);
pthread_cond_destroy(&_isempty);
}
void push(const T &in)
{
LockQueue();
while(isFull())//循环检测确保一定是因为不满足条件跳出循环
{
ProductWait();
}
_bq.push(in);
WakeupConsumer();
UnlockQueue();
}
void pop(T *out)
{
LockQueue();
while(isEmpty())
{
ConsumerWait();
}
*out = _bq.front();
_bq.pop();
WakeupProducter();
UnlockQueue();
}
private:
bool isFull()
{
return _bq.size() == _cap;
}
bool isEmpty()
{
return _bq.size() == 0;
}
void LockQueue()
{
pthread_mutex_lock(&_mtx);
}
void UnlockQueue()
{
pthread_mutex_unlock(&_mtx);
}
void ProductWait()
{
pthread_cond_wait(&_isempty,&_mtx);
}
void ConsumerWait()
{
pthread_cond_wait(&_isfull,&_mtx);
}
void WakeupProducter()
{
pthread_cond_signal(&_isempty);
}
void WakeupConsumer()
{
pthread_cond_signal(&_isfull);
}
private:
std::queue<T> _bq;
int _cap;
pthread_mutex_t _mtx;
pthread_cond_t _isfull;
pthread_cond_t _isempty;
};
}
3 基于环形队列的生产消费模型
将中间的仓库使用环形队列的结构。环形队列通过数组模拟,通过取余运算达到环形,同时利用信号量计数来对队列进行判空或判满。
代码实现
#pragma once
#include <iostream>
#include <vector>
#include <semaphore.h>
#include <pthread.h>
namespace ns_ring_queue
{
const int g_cap_default =10;
template<class T>
class RingQueue
{
public:
RingQueue(int cap = g_cap_default)
:_ring_queue(cap),_cap(cap),_c_step(0),_p_step(0)
{
sem_init(&_blank_sem,0,cap);
sem_init(&_data_sem,0,0);
pthread_mutex_init(&_c_mtx,nullptr);
pthread_mutex_init(&_p_mtx,nullptr);
}
~RingQueue()
{
sem_destroy(&_blank_sem);
sem_destroy(&_data_sem);
pthread_mutex_destroy(&_c_mtx);
pthread_mutex_destroy(&_p_mtx);
}
void pop(T* out)
{
sem_wait(&_data_sem);
pthread_mutex_lock(&_c_mtx);
*out = _ring_queue[_c_step];
_c_step++;
_c_step %= _cap;
pthread_mutex_unlock(&_c_mtx);
sem_post(&_blank_sem);
}
void push(const T& in)//==生产
{
sem_wait(&_blank_sem);
pthread_mutex_lock(&_p_mtx);
_ring_queue[_p_step] = in;
_p_step++;
_p_step %= _cap;
pthread_mutex_unlock(&_p_mtx);
sem_post(&_data_sem);
}
private:
std::vector<T> _ring_queue;
int _cap;
sem_t _blank_sem;
sem_t _data_sem;
int _c_step;
int _p_step;
pthread_mutex_t _c_mtx;
pthread_mutex_t _p_mtx;
};
} // namespace ns_ring_queue