生产者和消费者问题是线程模型中的经典问题。所谓的生产者和消费者模型是指生产者和消费者在同一时间段内共用同一个存储空间,生产者往存储空间中添加产品,消费者从存储空间中取走产品,当存储空间为空时,消费者阻塞,当存储空间满时,生产者阻塞。
他们之间的关系:
- 生产者与生产者之间是互斥关系,即同一时刻只能有一个生产者进行“生产”
- 消费者与消费者之间是互斥关系,即同一时刻只能有一个消费者进行“消费”
- 生产者与消费者之间是同步与互斥关系,即消费者“消费”和生产者“生产”不能同时进行
基于BlockingQueue(阻塞队列)的生产者消费者模型
#include <iostream>
#include <queue>
#include <pthread.h>
#include <stdio.h>
#include <unistd.h>
#define MAX_CAPACITY 5
using namespace std;
class Queue{
private:
queue<int> _store; //初始化一个存放数据的队列
int _capacity;//队列的总容量
pthread_mutex_t mutexs;//互斥锁
pthread_cond_t cond_Preducer;//生产者的条件变量(既当满足这个条件时,生产者就可以进行相关的操作)
pthread_cond_t cond_Consumer;//消费者的条件变量(既当满足这个条件时,消费者就可以进行相关的操作)
public:
Queue(int capacity = MAX_CAPACITY)//构造函数 将队列的总容量设为5
:_capacity(capacity)
{
pthread_mutex_init(&mutexs, NULL);//初始化互斥锁
pthread_cond_init(&cond_Consumer, NULL);//初始化消费者条件变量
pthread_cond_init(&cond_Preducer, NULL);//初始化生产者条件变量
}
~Queue()//析构函数
{
pthread_mutex_destroy(&mutexs);//释放互斥锁所占用的资源
pthread_cond_destroy(&cond_Consumer);//销毁消费者条件变量
pthread_cond_destroy(&cond_Preducer);//销毁生产者条件变量
}
bool push(const int& data)//生产者将数据放入队列
{
pthread_mutex_lock(&mutexs);//上锁
while(_capacity ==_store.size())//判断当前队列是否已满
{//如果队列满,则
pthread_cond_signal(&cond_Consumer);//至少唤醒一个阻塞的消费者线程,即标记消费者条件变量
pthread_cond_wait(&cond_Preducer,&mutexs);//此时该生产者线程进入阻塞状态,并将互斥锁解锁
}
//如果队列不满,则
_store.push(data);//插入数据
pthread_cond_signal(&cond_Consumer);//至少唤醒一个阻塞的消费者线程,即标记消费者条件变量
pthread_mutex_unlock(&mutexs);//解锁
return true;
}
bool pop(int& data)//消费者将数据取出队列
{
pthread_mutex_lock(&mutexs);//上锁
while(_store.empty())//判断队列是否为空
{//如果队列为空,则
pthread_cond_signal(&cond_Preducer);//至少唤醒一个阻塞的生产者者线程,即标记生产者条件变量
pthread_cond_wait(&cond_Consumer,&mutexs);//此时该消费者线程进入阻塞状态,并将互斥锁解锁
}
//如果队列不为空,则
data = _store.front();//从队列中取出一个元素,这里取出的是当前队列的第一个元素
_store.pop();//pop操作
pthread_cond_signal(&cond_Preducer);//至少唤醒一个阻塞的生产者线程,即标记生产者条件变量
pthread_mutex_unlock(&mutexs);//解锁
return true;
}
};
void* producter(void* arg)//生产者线程函数
{
srand((unsigned) time(NULL)); //随机种子函数
Queue* p = (Queue*)arg;
while(1)
{//生产者生产一个数据
int data = rand()%11;
p->push(data);
printf("生产者生产了一个数据: %d\n",data);
}
return NULL;
}
void* consumer(void* arg)//消费者线程函数
{
Queue* p = (Queue*)arg;
int data = 0;
while(1)
{//消费者消费一个数据
p->pop(data);
printf("\t\t\t\t消费者使用了一个数据: %d\n", data);
}
return NULL;
}
int main()
{
pthread_t Consumer;
pthread_t Preducer;
Queue arr;
pthread_create(&Consumer, NULL, consumer,(void*)&arr);//创建一个消费者线程
pthread_create(&Preducer, NULL, producter,(void*)&arr);//创建一个生产者线程
pthread_join(Consumer,NULL);//阻塞等待,并释放消费者线程所占用资源
pthread_join(Preducer,NULL);//阻塞等待,并释放生产者线程所占用资源
return 0;
}
使用以下命令进行编译链接
g++ -o main test.cpp -lpthread
【执行结果 】
基于BlockingList(阻塞链表)的生产者消费者模型
#include<stdlib.h>
#include<assert.h>
#include<pthread.h>
#include<stdio.h>
#include<time.h>
#include<unistd.h>
typedef int elemtype;//元素类型
#define MAX 20//链表的最大元素个数
typedef struct Node//节点类型
{
elemtype data;
struct Node *next;
}Node;
typedef struct list
{
Node* head;//head永远指向链表的头节点
Node* rear;//rear永远指向链表的尾节点
int num = 0;//num用来记录链表中的元素个数
}list;
list List;//全局变量or共享资源
pthread_cond_t cond_Preducer = PTHREAD_COND_INITIALIZER;//生产者的条件变量
pthread_cond_t cond_Consumer = PTHREAD_COND_INITIALIZER;//消费者的条件变量
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;//互斥锁
void create_list(list* List)//初始化链表
{
Node* head = (Node*)malloc(sizeof(Node));//头结点
assert(head != NULL);
head->next == NULL;
List->head = head;
List->rear = head;
List->num = 0;
}
void Free_list(list* List)//释放链表
{
Node* p = NULL;
while(List->head != NULL)
{
p = List->head;
List->head = List->head->next;
free(p);
}
List->head = List->rear = NULL;//List是在栈上开辟的,进程结束时会自动释放
List->num = 0;
}
void insert_list(list* List,elemtype data)//生产者将数据插入链表
{
if(List->num >= MAX){//判断此时链表是否已满
return;
}
Node* pnew = (Node*)malloc(sizeof(Node));
assert(pnew != NULL);
pnew->data = data;
pnew->next = NULL;
List->rear->next = pnew;
List->rear = pnew;
List->num++;
}
void delete_list(list* List)//消费者将数据从链表中取出
{
if(List->num == 0){//判断链表是否为空
return;
}
Node* p = List->head->next;
List->head->next = List->head->next->next;
free(p);
List->num--;
//删除最后一个节点时,要特殊处理
if(List->num == 0){
List->rear = List->head;
}
}
//生产者线程函数
void *producer(void *arg)
{
pthread_detach(pthread_self());//将该线程设为分离状态,及线程结束后会自动释放所占用资源
srand((unsigned)time(NULL));//初始化随机种子
while(1)
{
pthread_mutex_lock(&mutex);//上锁
while(List.num == MAX)//如果此时链表已满
{
pthread_cond_signal(&cond_Consumer);//则至少唤醒一个阻塞线程
pthread_cond_wait(&cond_Preducer, &mutex);//等待自身条件
}
int data = rand()%11;
insert_list(&List, data);
printf("生产者生产了一个数据:%d\n",data);
pthread_cond_signal(&cond_Consumer);//则至少唤醒一个阻塞线程
pthread_mutex_unlock(&mutex);//解锁
}
}
void *consumer(void *arg)//消费者线程函数
{
pthread_detach(pthread_self());
while(1)
{
pthread_mutex_lock(&mutex);//上锁
while(List.num == 0)
{//没有产品,消费者就阻塞,直到被唤醒
pthread_cond_signal(&cond_Preducer);则至少唤醒一个阻塞线程
pthread_cond_wait(&cond_Consumer, &mutex);//等待自身条件
}
printf("\t\t\t\t消费者消费了一个数据:%d\n",List.head->next->data);
delete_list(&List);
pthread_cond_signal(&cond_Preducer);//则至少唤醒一个阻塞线程
pthread_mutex_unlock(&mutex);//解锁
}
}
int main()
{
create_list(&List);
pthread_t Consumer;
pthread_t Preducer;
pthread_create(&Preducer, NULL, producer, NULL);
pthread_create(&Consumer, NULL, consumer, NULL);
getchar();//阻塞,不让主函数结束
Free_list(&List);
return 0;
}