生产者与消费者模型:线程安全的队列(线程与线程之间对临界资源访问的一种编程思想)
功能:支持忙闲不均,解耦合,支持并发(线程安全)
场所:缓冲区。
角色:生产者,消费者
关系:三种关系 在生产者与消费者模型之中保证这么三种关系的实现,
生产者与生产者:互斥
生产者与消费者:同步与互斥
消费者与消费者:互斥
先来看一个错误的写法:
#include <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<queue>
using namespace std;
#define QUEUE_MAX 10
class BlockQueue
{
public:
BlockQueue(int capacity = QUEUE_MAX):_capacity(capacity)
{
pthread_mutex_init(&_mutex, NULL);
pthread_cond_init(&_full, NULL);
pthread_cond_init(&_empty, NULL);
}
~BlockQueue()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_full);
pthread_cond_destroy(&_empty);
}
void push(int data)
{
pthread_mutex_lock(&_mutex);
//用if是错误的
if(_capacity == _list.size())
{
cout << "---------------full" << endl;
pthread_cond_wait(&_full, &_mutex);
}
_list.push(data);
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_empty);
}
void pop(int* data)
{
pthread_mutex_lock(&_mutex);
if(_list.empty())
{
cout << "---------------empty" << endl;
pthread_cond_wait(&_empty, &_mutex);
}
*data = _list.front();
_list.pop();
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_full);
}
private:
queue<int> _list;
size_t _capacity;
pthread_mutex_t _mutex;
pthread_cond_t _full;
pthread_cond_t _empty;
};
BlockQueue q;
int i = 1;
void* productor(void *arg)
{
while(1)
{
cout << "productor_pthread:"<< arg << " product:" << i << endl;
q.push(i++);
}
return NULL;
}
void* consumer(void* arg)
{
while(1)
{
int data;
q.pop(&data);
cout << "consumer_pthread:" << arg << " consume:" << data << endl;
}
return NULL;
}
int main()
{
pthread_t tid1[4];
pthread_t tid2[4];
int ret;
for(int i = 0; i < 4; ++i)
{
ret = pthread_create(&tid1[i], NULL, productor, (void*)i);
if(0 != ret)
{
cout << "create pthread error" << endl;
return -1;
}
}
for(int i = 0; i < 4; ++i)
{
ret = pthread_create(&tid2[i], NULL, consumer, (void*)i);
if(0 != ret)
{
cout << "create pthread error" << endl;
return -1;
}
}
for(int i = 0; i < 4; i++)
{
pthread_join(tid1[i], NULL);
pthread_join(tid2[i], NULL);
}
return 0;
}
很明显,这个结果中,队列满了依然往里面添加任务。
原因:
同样当队列只有一个元素的时候,先来的消费者拿走了这个元素,后面来的线程就会越界访问导致代码奔溃。
正确的如下:
把临界条件的判断改为while。
#include <iostream>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<queue>
using namespace std;
#define QUEUE_MAX 10
class BlockQueue
{
public:
BlockQueue(int capacity = QUEUE_MAX):_capacity(capacity)
{
pthread_mutex_init(&_mutex, NULL);
pthread_cond_init(&_full, NULL);
pthread_cond_init(&_empty, NULL);
}
~BlockQueue()
{
pthread_mutex_destroy(&_mutex);
pthread_cond_destroy(&_full);
pthread_cond_destroy(&_empty);
}
void push(int data)
{
pthread_mutex_lock(&_mutex);
//用if是错误的
while(_capacity == _list.size())
{
cout << "---------------full" << endl;
pthread_cond_wait(&_full, &_mutex);
}
_list.push(data);
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_empty);
}
void pop(int* data)
{
pthread_mutex_lock(&_mutex);
while(_list.empty())
{
cout << "---------------empty" << endl;
pthread_cond_wait(&_empty, &_mutex);
}
*data = _list.front();
_list.pop();
pthread_mutex_unlock(&_mutex);
pthread_cond_signal(&_full);
}
private:
queue<int> _list;
size_t _capacity;
pthread_mutex_t _mutex;
pthread_cond_t _full;
pthread_cond_t _empty;
};
BlockQueue q;
int i = 1;
void* productor(void *arg)
{
while(1)
{
cout << "productor_pthread:"<< arg << " product:" << i << endl;
q.push(i++);
}
return NULL;
}
void* consumer(void* arg)
{
while(1)
{
int data;
q.pop(&data);
cout << "consumer_pthread:" << arg << " consume:" << data << endl;
}
return NULL;
}
int main()
{
pthread_t tid1[4];
pthread_t tid2[4];
int ret;
for(int i = 0; i < 4; ++i)
{
ret = pthread_create(&tid1[i], NULL, productor, (void*)i);
if(0 != ret)
{
cout << "create pthread error" << endl;
return -1;
}
}
for(int i = 0; i < 4; ++i)
{
ret = pthread_create(&tid2[i], NULL, consumer, (void*)i);
if(0 != ret)
{
cout << "create pthread error" << endl;
return -1;
}
}
for(int i = 0; i < 4; i++)
{
pthread_join(tid1[i], NULL);
pthread_join(tid2[i], NULL);
}
return 0;
}