生产者消费者模型,使用链表来实现,生产者依次创建链表节点,消费者访问链表中节点的数据域,然后删除(消费)。
创建两个线程来实现的过程中会产生一些问题,例如节点还未创建出来,消费者线程先得到CPU先执行,会出现错误等。
因此引入条件变量,等待生产者进程执行后,消费者进程在执行就不会发生错误了。
条件变量
- 条件本身不是锁!但它也可以造成线程阻塞。通常与互斥锁配合使用。给多线程提供一个会合的场所。
- 使用互斥量保护共享数据;
- 使用条件变量可以使线程阻塞, 等待某个条件的发生, 当条件满足的时候解除阻塞.
- 条件变量的两个动作:
- 条件不满足, 阻塞线程
- 条件满足, 通知阻塞的线程解除阻塞, 开始工作.
相关函数:
1 定义条件变量
pthread_cont_t cond;
2 初始化条件变量
pthread_cond_init(&cond, NULL);
3 在生成者线程中调用:
pthread_cond_signal(&cond);
4 在消费者线程中调用:
pthread_cond_wait(&cond, &mutex);
5 释放条件变量
pthread_cond_destroy(&cond);
代码如下:
//使用条件变量实现生产者和消费者模型
#include<iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>
#include <pthread.h>
using namespace std;
typedef struct node
{
int data;
struct node *next;
}NODE;
NODE *head = NULL;
//定义一把锁
pthread_mutex_t mutex;
//定义条件变量
pthread_cond_t cond;
//生产者线程
void *producer(void *arg)
{
NODE *pNode = NULL;
while(1)
{
//生产一个节点
pNode = (NODE *)malloc(sizeof(NODE));
if(pNode==NULL)
{
perror("malloc error");
exit(-1);
}
pNode->data = rand()%1000;
printf("P:[%d]\n", pNode->data);
//加锁
pthread_mutex_lock(&mutex);
pNode->next = head;
head = pNode;
//解锁
pthread_mutex_unlock(&mutex);
//通知消费者线程解除阻塞
pthread_cond_signal(&cond);
sleep(rand()%3);
}
}
//消费者线程
void *consumer(void *arg)
{
NODE *pNode = NULL;
while(1)
{
//加锁
pthread_mutex_lock(&mutex);
if(head==NULL)
{
//若条件不满足,需要阻塞等待
//若条件不满足,则阻塞等待并解锁;
//若条件满足(被生成者线程调用pthread_cond_signal函数通知),解除阻塞并加锁
pthread_cond_wait(&cond, &mutex);
}
cout << "C:[" << head->data << "]" << endl;
pNode = head;
head = head->next;
//解锁
pthread_mutex_unlock(&mutex);
free(pNode);
pNode = NULL;
sleep(rand()%3);
}
}
int main()
{
int ret;
pthread_t thread1;
pthread_t thread2;
//初始化互斥锁
pthread_mutex_init(&mutex, NULL);
//条件变量初始化
pthread_cond_init(&cond, NULL);
//创建生产者线程
ret = pthread_create(&thread1, NULL, producer, NULL);
if(ret!=0)
{
printf("pthread_create error, [%s]\n", strerror(ret));
return -1;
}
//创建消费者线程
ret = pthread_create(&thread2, NULL, consumer, NULL);
if(ret!=0)
{
printf("pthread_create error, [%s]\n", strerror(ret));
return -1;
}
//等待线程结束
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
//释放互斥锁
pthread_mutex_destroy(&mutex);
//释放条件变量
pthread_cond_destroy(&cond);
return 0;
}
运行结果如下:消费者访问的就是生产者最后一次产生的节点;有连续生产的说明sleep(rand()%3)是零,没有让出CPU资源导致的。