生产者消费者模型是多线程案例中经常用到的一种模型,有专门的线程在负责生产产品(这个产品指代程序所需的数据、文件等等),有专门的线程在负责取出生产出来的产品用以提供程序使用(消费)。因为生产和消费在程序中是不定时间的,我们也无法确定什么时候需要生产产品,什么时候需要消费产品。所以就有了使用条件变量实现的解决方案。


#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>

struct tag_product {
struct tag_product* next;
int data;
};
struct tag_product* head;

// 初始化条件变量和锁的另外一种方式,也可以使用init
pthread_cond_t product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;

void* producer(void* arg)
{
struct tag_product* cur;
while (1)
{
// 加锁
pthread_mutex_lock(&mutex);
// 创建新节点
cur = (struct tag_product*)malloc(
sizeof(struct tag_product));
// 让新节点先有所指向
cur->next = head->next;
// 让头节点指向新来的节点
head->next = cur;

// 解锁
pthread_mutex_unlock(&mutex);
// 让其他线程得到新产品通知
pthread_cond_signal(&product);
sleep(rand() % 5);
}
return (void*)0;
}

void* consumer(void* arg)
{
printf(“consumer thread = %d\n”, (unsigned int)pthread_self());
struct tag_product* tmp;
while(1)
{
// 加锁
pthread_mutex_lock(&mutex);
while(head->next == NULL)
{
// 等待,循环判断头节点是否有下一个节点
pthread_cond_wait(&product, &mutex);
}
// 有新节点则备份第一个节点
tmp = head->next;
// 让头节点跳过第一个节点
head->next = tmp->next;
// 打印第一个节点的数据
printf(“consumer %d\n”, tmp->data);

// 释放第一个节点
free(tmp);
// 解锁
pthread_mutex_unlock(&mutex);
sleep(rand() % 5);
}
return (void*)0;
}

int main(int argc, char* argv[])
{
pthread_t pid, cid;
srand(time(NULL));

head = (struct tag_product*)malloc(sizeof(struct tag_product));
head->next = NULL;

pthread_create(&pid, NULL, producer, (void*)1);
pthread_create(&cid, NULL, consumer, (void*)1);

pthread_join(pid,NULL);
pthread_join(cid,NULL);
return 0;
}