理解
生产者消费者模型就像生活中的中介公司,他提供了一个生产者(卖方)和消费者(买方)的平台。
让生产者不需要操心资源的生产的快慢,让消费者不用担心资源的来源。保证了“交易”的达成。
优点
- 解耦合:消费者和生产不需要对数据进行交互
- 可并发:不同类型线程可以同时对缓冲队列进行操作
- 支持忙闲不均:即生产者与消费者的快慢程度不一
特点
一个场所:指缓冲区
两个对象:生产者和消费者
三种关系:
1.生产者与生产者之间互斥
2.消费者与消费者之间互斥
3.生产者与消费者之间同步
实现
使用信号量实现
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
#include <vector>
#include <semaphore.h>
using namespace std;
#define max_queue 10
//模拟一个阻塞队列的生产者消费者模型
class BlockQueue
{
private:
vector<int> queue;
int capacity;
int _step_read;
int _step_write;
sem_t con_lock;
sem_t pro_lock;
sem_t sem_con;
sem_t sem_pro;
public:
BlockQueue(int max_q = max_queue):capacity(max_q),queue(max_q),_step_read(0),_step_write(0)
{
sem_init(&con_lock,0,1);
sem_init(&pro_lock,0,1);
sem_init(&sem_con,0,0);
sem_init(&sem_pro,0,max_q);
}
~BlockQueue()
{
sem_destroy(&con_lock);
sem_destroy(&pro_lock);
sem_destroy(&sem_con);
sem_destroy(&sem_pro);
}
bool queue_push(int &data)
{
//1.使用信号量等待,判断是否有位置可插入数据
sem_wait(&sem_pro);
//2.先上锁
//这里的锁目的是为了保护数据访问的,不能放在条件判断之前
//如果放在信号量判断之前,若消费者信号量阻塞,则会产生死锁
sem_wait(&pro_lock);
//3.插入数据
queue[_step_write]=data;
//求余操作保证_step_write的范围
_step_write = (_step_write +1 )% capacity;
//4.唤醒消费者进行取数据
sem_post(&sem_con);
//5.解锁
sem_post(&pro_lock);
}
bool queue_pop(int &data)
{
//1.使用信号量等待,判断是否还有资源可以获取
sem_wait(&sem_con);
//2.上锁//这里的上锁目的是和相同线程间进行互斥
//本来应该不同角色设置一把锁,如果是多核CPU就能实现并发
sem_wait(&con_lock);
//3.进行获取数据操作
data = queue[_step_read];
_step_read = (_step_read + 1)% capacity;
//4.唤醒生产者可以进行数据的插入了
sem_post(&sem_pro);
//5.解锁
sem_post(&con_lock);
}
};
void *thr_con(void *arg)
{
BlockQueue *queue = (BlockQueue*)arg;
while(1)
{
int data;
queue->queue_pop(data);
printf("**get a data %d \n",data);
}
return NULL;
}
void *thr_pro(void *arg)
{
BlockQueue *queue = (BlockQueue*)arg;
int data = 0;
while(1)
{
queue->queue_push(data);
printf("--push a data %d \n",data++);
}
return NULL;
}
#define MAX_THR 4
int main()
{
int ret;
pthread_t ctid[MAX_THR],ptid[MAX_THR];
BlockQueue _queue;
for(int i=0; i<MAX_THR; i++)
{
ret= pthread_create(&ctid[i],NULL,thr_con,(void*)&_queue);
if(ret!=0)
{
printf("create thread error\n");
return -1;
}
}
for(int i=0; i<MAX_THR; i++)
{
ret= pthread_create(&ptid[i],NULL,thr_pro,(void*)&_queue);
if(ret!=0)
{
printf("create thread error\n");
return -1;
}
}
for(int i=0; i<MAX_THR; i++)
{
pthread_join(ctid[i],NULL);
pthread_join(ptid[i],NULL);
}
return 0;
}
使用条间变量和互斥锁实现
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <pthread.h>
#include <queue>
using namespace std;
#define MAX_THR 4
class BlockQueue
{
private:
std::queue<int> _queue;//设置动态增长队列
int _capacity;//确定队列的最大容量
pthread_cond_t _cond_consumer;//消费者等待队列
pthread_cond_t _cond_productor;//生产者等待队列
pthread_mutex_t con_mutex;//设置互斥锁
pthread_mutex_t pro_mutex;//设置互斥锁
public:
BlockQueue(int max_queue = 10):_capacity(max_queue)
{
pthread_cond_init(&_cond_consumer,NULL);
pthread_cond_init(&_cond_productor,NULL);
pthread_mutex_init(&con_mutex,NULL);
pthread_mutex_init(&pro_mutex,NULL);
}
~BlockQueue()
{
pthread_cond_destroy(&_cond_consumer);
pthread_cond_destroy(&_cond_productor);
pthread_mutex_destroy(&con_mutex);
pthread_mutex_destroy(&pro_mutex);
}
//提供给生产者的接口,数据入队
bool queue_push(int &data)
{
pthread_mutex_lock(&pro_mutex);
while(_queue.size() == _capacity)//判断队列节点是否添加满了
{
pthread_cond_wait(&_cond_productor,&pro_mutex);
}
_queue.push(data);
pthread_mutex_unlock(&pro_mutex);
pthread_cond_signal(&_cond_consumer);
return true;
}
//提供给消费者的接口————数据出口
bool queue_pop(int &data)
{
pthread_mutex_lock(&con_mutex);
while(_queue.empty())
{
pthread_cond_wait(&_cond_consumer,&con_mutex);
}
data=_queue.front();
_queue.pop();
pthread_mutex_unlock(&con_mutex);
pthread_cond_signal(&_cond_productor);
return true;
}
};
void *thr_consumer(void *arg)
{
BlockQueue* b=(BlockQueue*)arg;
while(1)
{
int data;
b->queue_pop(data);
printf("i get a data %d\n",data);
}
return NULL;
}
void *thr_productor(void *arg)
{
int data = 0;
BlockQueue* b=(BlockQueue*)arg;
while(1)
{
b->queue_push(data);
printf("i put a data %d\n",data++);
}
return NULL;
}
int main()
{
pthread_t ctid[MAX_THR],ptid[MAX_THR];
BlockQueue queue;
for(int i=0;i<MAX_THR;i++)
{
int ret=pthread_create(&ctid[i],NULL,thr_consumer,(void*)&queue);
if(ret!=0)
{
printf("create thr error\n");
return -1;
}
}
for(int i=0;i<MAX_THR;i++)
{
int ret=pthread_create(&ctid[i],NULL,thr_productor,(void*)&queue);
if(ret!=0)
{
printf("create thr error\n");
return -1;
}
}
for(int i=0;i<MAX_THR;i++)
{
pthread_join(ptid[i],NULL);
pthread_join(ctid[i],NULL);
}
return 0;
}