生产者与消费者模型
一种特殊的设计模式
针对场景
有大量数据的产生以及处理的场景。
生产者消费者模式就是通过一个容器来解决生产者和消费者的强耦合问题。生产者和消费者彼此之间不直接通讯,
而通过阻塞队列来进行通讯,所以生产者生产完数据之后不用等待消费者处理,直接扔给阻塞队列,消费者不找生
产者要数据,而是直接从阻塞队列里取,阻塞队列就相当于一个缓冲区,平衡了生产者和消费者的处理能力。这个
阻塞队列就是用来给生产者和消费者解耦的
生产者与消费者模型的优点
解耦合、支持并发、支持忙闲不均
实现
生产者与消费者无非就是两类执行流+线程安全的任务队列。
条件变量+互斥锁
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <queue>
#include <mutex>
#include <pthread.h>
#define MAXQ 10
class BlockQueue
{
private:
std::queue<int> _queue;
int _capacity;
pthread_mutex_t _mutex;
pthread_cond_t _cond_pro;
pthread_cond_t _cond_con;
public:
BlockQueue(int maxq = MAXQ):_capacity(maxq){
pthread_mutex_init(&_mutex, NULL);
pthread_cond_init(&_cond_pro, NULL);
pthread_cond_init(&_cond_con, NULL);
}
~BlockQueue() {
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_cond_pro);
pthread_cond_destroy(&_cond_con);
}
bool Push(int data){
pthread_mutex_lock(&_mutex);
while(_queue.size() == _capacity) {
pthread_cond_wait(&_cond_pro, &_mutex);
}
_queue.push(data);
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond_con);
return true;
}
bool Pop(int *data) {
pthread_mutex_lock(&_mutex);
while(_queue.empty() == true) {
pthread_cond_wait(&_cond_con, &_mutex);
}
*data = _queue.front();
_queue.pop();
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_cond_pro);
return true;
}
};
std::mutex g_mutex;
void *consumer(void *arg)
{
BlockQueue *q = (BlockQueue*)arg;
int data;
while(1) {
q->Pop(&data);
printf("%p- pop data:%d\n", pthread_self(), data);
}
return NULL;
}
void *productor(void *arg)
{
BlockQueue *q = (BlockQueue*)arg;
int i = 0;
while(1) {
q->Push(i);
printf("%p push data:%d\n", pthread_self(), i++);
}
return NULL;
}
int main()
{
pthread_t ctid[4], ptid[14];
int ret;
BlockQueue q;
for (int i = 0; i < 4; i++) {
ret = pthread_create(&ctid[i], NULL, consumer, (void*)&q);
if (ret != 0) {
printf("thread create error\n");
return -1;
}
}
for (int i = 0; i < 14; i++) {
ret = pthread_create(&ptid[i], NULL, productor, (void*)&q);
if (ret != 0) {
printf("thread create error\n");
return -1;
}
}
for (int i = 0; i < 4; i++) {
pthread_join(ctid[i], NULL);
pthread_join(ptid[i], NULL);
}
return 0;
}
信号量+环形队列
#include <iostream>
#include <cstdlib>
#include <vector>
#include <pthread.h>
#include <semaphore.h>
#define MAXQ 5
class RingQueue{
private:
std::vector<int> _arry;
int _capacity;
int _write_step;
int _read_step;
sem_t _sem_idle;//
sem_t _sem_data;
sem_t _sem_lock;
public:
RingQueue(int maxq = MAXQ):_arry(maxq),
_capacity(maxq), _write_step(0), _read_step(0){
//sem_init(信号量,1进程/0线程,初值)
sem_init(&_sem_idle, 0, maxq);
sem_init(&_sem_data, 0, 0);//初始没有数据
sem_init(&_sem_lock, 0, 1);
}
~RingQueue(){
sem_destroy(&_sem_idle);
sem_destroy(&_sem_data);
sem_destroy(&_sem_lock);
}
bool Push(const int data){
sem_wait(&_sem_idle);//空闲空间-1
sem_wait(&_sem_lock);//加锁
_arry[_write_step] = data;
_write_step = (_write_step+1)%_capacity;
sem_post(&_sem_lock);//解锁
sem_post(&_sem_data);//数字资源+1
return true;
}
bool Pop(int *data){
sem_wait(&_sem_data);//数据资源-1
sem_wait(&_sem_lock);//加锁
*data = _arry[_read_step];
_read_step = (_read_step+1)%_capacity;
sem_post(&_sem_lock);//解锁
sem_post(&_sem_idle);//空闲空间+1
return true;
}
};
void *consumer(void *arg)
{
RingQueue *q = (RingQueue*)arg;
int data;
while(1) {
q->Pop(&data);
printf("%p- pop data:%d\n", pthread_self(), data);
}
return NULL;
}
void *productor(void *arg)
{
RingQueue *q = (RingQueue*)arg;
int i = 0;
while(1) {
q->Push(i);
printf("%p push data:%d\n", pthread_self(), i++);
}
return NULL;
}
int main()
{
pthread_t ctid[4], ptid[14];
int ret;
RingQueue q;
for (int i = 0; i < 4; i++) {
ret = pthread_create(&ctid[i], NULL, consumer, (void*)&q);
if (ret != 0) {
printf("thread create error\n");
return -1;
}
}
for (int i = 0; i < 4; i++) {
ret = pthread_create(&ptid[i], NULL, productor, (void*)&q);
if (ret != 0) {
printf("thread create error\n");
return -1;
}
}
for (int i = 0; i < 4; i++) {
pthread_join(ctid[i], NULL);
pthread_join(ptid[i], NULL);
}
return 0;
}