生产者(producer)和消费者(consumer)问题是并发处理中最常见的一类问题,是一个多线程同步问题的经典案例。
可以这样描述这个问题,有一个或者多个生产者产生某种类型的数据,并放置在固定大小的缓冲区中,一个消费者从缓冲区中取数据,每次取一项,系统必须保证对缓冲区的重复操作,任何时候,只有一个生产者或者消费者可以访问缓冲区;同时,消费者只能在缓冲区不为空的时候从缓冲区中读数据,生产者只能在缓冲区不为满的时候向缓冲区写入数据。
上面的问题总结起来有两点:
第一是缓冲区的互斥访问问题,任意时刻最多只能有一个线程访问缓冲区,Linux下可以使用互斥量pthread_mutex_t对访问缓冲区的临界区代码进行保护。
第二是生产者和消费者对缓冲区访问的同步问题,生产者在缓冲区满时不能向缓冲区中写入数据,同时消费者在缓冲区空时不能读取数据,这里采用条件变量来对缓冲区进行同步。
实现代码如下:
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <assert.h>
pthread_mutex_t mylock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t mycond = PTHREAD_COND_INITIALIZER;
typedef struct _node
{
int data;
struct _node *next;
}node_t, *node_p, **node_pp;
node_p alloc_node(int data)
{
node_p _n = (node_p)malloc(sizeof(node_t));
if(_n == NULL)
{
perror("malloc");
return NULL;
}
_n->data = data;
_n->next = NULL;
return _n;
}
void del_node(node_p _n)
{
assert(_n);
free(_n);
}
int is_empty(node_p list)
{
assert(list);
if(list->next)
{
return 0;
}
else
return 1;
}
void show_list(node_p list)
{
assert(list);
node_p start = list->next;
while(start)
{
printf("%d\n",start->data);
start = start->next;
}
printf("\n");
}
void init_list(node_pp _h)
{
*_h = alloc_node(0);
}
void Push(node_p list, int data)
{
assert(list);
node_p new_node = alloc_node(data);
new_node->next = list->next;
list->next = new_node;
}
void Pop(node_p list, int *data)
{
assert(list);
assert(data);
if(is_empty(list))
{
printf("list is empty\n");
}
node_p _n = list->next;
list->next = _n->next;
*data = _n->data;
del_node(_n);
}
void destory_list(node_p list)
{
assert(list);
int data = 0;
while(!is_empty(list))
{
Pop(list, &data);
}
del_node(list);
}
void test_list(node_p head)
{
int i = 0;
for( ; i<10; i++)
{
Push(head, i);
sleep( 1 );
show_list(head);
}
int data = 0;
for(; i>=5; i--)
{
Pop(head, &data);
sleep(1);
show_list(head);
}
}
void *thread_product(void* arg)
{
node_p head = (node_p)arg;
while(1)
{
usleep(100621);
int data = rand()%10000;
pthread_mutex_lock(&mylock);
Push(head, data);
pthread_mutex_unlock(&mylock);
pthread_cond_signal(&mycond);
printf("product data is: %d\n", data);
}
}
void *thread_consumer(void* arg)
{
node_p head = (node_p)arg;
int data = 0;
while(1)
{
pthread_mutex_lock(&mylock);
while(is_empty(head))
{
pthread_cond_wait(&mycond, &mylock);
}
Pop(head, &data);
pthread_mutex_unlock(&mylock);
printf("consumer done, data is: %d\n",data);
}
}
int main()
{
node_p head = NULL;
init_list(&head);
//test_list(head);
pthread_t tid1, tid2;
pthread_create(&tid1, NULL, thread_product, (node_p)head);
pthread_create(&tid2, NULL, thread_consumer, (node_p)head);
pthread_join(tid1, NULL);
pthread_join(tid2, NULL);
destory_list(head);
show_list(head);
pthread_mutex_destroy(&mylock);
pthread_cond_destroy(&mycond);
show_list(head);
//sleep(1);
return 0;
}
实现结果
如下图所示:因为我在编程时用了产生随机数的函数rand(),所以数字产生是随机的。