一、生产者-消费者问题

    同步和互斥是进程间很重要的交互模式,而生产者和消费者问题则是同步和互斥的一个经典模型。

    同步是一种时序关系。如规定了进程1 处理完事情A后,进程2 才能处理事情 B,经典的同步问题是生产者和消费者间的同步。

    互斥描述的是一种独占关系。如任一时刻,进城1 和进程2 中只能有一个写文件C 


    生产者-消费者问题

       1、在同一个进程地址空间内执行的两个线程生产者线程生产物品,然后将物品放置在一个空缓冲区中供消费者线程消费。消费者线程从缓冲区中获得物品,然后释放缓冲区。当生产者线程生产物品时,如果没有空缓冲区可用,那么生产者线程必须等待消费者线程释放出一个空缓冲区。当消费者线程消费物品时,如果没有满的缓冲区,那么消费者线程将被阻塞,直到新的物品被生产出来。

       2、生产者中先同步再互斥,而消费者先互斥再同步,或反之;以及生产者和消费者都先互斥再同步这几种情况都不会死锁,因为它们间并没有交叉关系,就更不可能形成死锁环。之所以先同步,再互斥,是为了更好的并发性:并发性的瓶颈是互斥区,先同步再互斥,使得互斥区代码更短。

二、条件变量

     条件变量(Condition Variable):线程A需要等某个条件成立才能继续往下执行,现在这个条件不成立,线程A就阻塞等待,而线程B在执行过程中使这个条件成立了,就唤醒线程A继续执行。

     在pthread库中通过条件变量来阻塞等待一个条件,或者唤醒等待这个条件的线程。

     Condition Variable 用pthread_cond_t类型的变量表示,可以这样初始化和销毁.

    返回值:成功返回0,失败返回错误号。

     

     int pthread_cond_init(pthread_cond_t *restrict cond,

              const pthread_condattr_t *restrict attr);    //初始化

     pthread_cond_t cond = PTHREAD_COND_INITIALIZER;//定义条件变量

     int pthread_cond_destroy(pthread_cond_t *cond);  //销毁条件变量

       int pthread_cond_timedwait(pthread_cond_t *restrict cond,

              pthread_mutex_t *restrict mutex,

              const struct timespec *restrict abstime); //条件不成熟,等待

       int pthread_cond_wait(pthread_cond_t *restrict cond,

              pthread_mutex_t *restrict mutex);

    int pthread_cond_broadcast(pthread_cond_t *cond);  //广播式唤醒

    int pthread_cond_signal(pthread_cond_t *cond);  //唤醒等待的线程

    条件检测:pthtread_cond_wait() 放至while循环中,进行条件检测。


三、单 生产者-消费者模型:

    输入时,输入线程(插入等)是生产者,而计算线程是消费者;

    输出时,计算线程(删除等)是生产者,而打印线程是消费者。

    //链表:头进 尾出

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

typedef int data_type;
typedef int* data_type_p;

typedef struct _node
{
	data_type data;
	struct _node *next;
}node_t,*node_p,**node_pp;

pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
node_p head=NULL;

static node_p buy_node(data_type _data)
{
	node_p tmp=malloc(sizeof(node_p));
	if(tmp)
	{
		tmp->data=_data;
		tmp->next=NULL;
		return tmp;
	}
	return NULL;
}
void init_list(node_pp _phead)
{
	*_phead=buy_node(0);
}

void delete_node(node_p tmp)
{
	if(tmp)
	{
		free(tmp);
		tmp=NULL;
	}
}
int pop_node(node_p list,data_type_p _data_p)
{
	if(list->next == NULL)
	{
		*_data_p=-1;
		return -1;
	}
	node_p tmp=list->next;
	list->next=tmp->next;
	*_data_p=tmp->data;
	delete_node(tmp);
	return 0;
}

void push_node(node_p list,data_type _data)
{
	node_p tmp=buy_node(_data);
	tmp->next=list;
	list->next=tmp;
}

void show_list(node_p list)
{
	node_p cur=list;
	while(cur)
	{
		printf("%d ",cur->data);
		fflush(stdout);
		cur=cur->next;
	}
}

void *product(void *arg)
{
	int i=0;
	while(1)
	{
		pthread_mutex_lock(&lock);
		printf("product data:%d\n",i++);
		push_node(head,i++);
		printf("product done ... wakeup consumer\n");
		pthread_mutex_unlock(&lock);
		pthread_cond_signal(&cond);
		sleep(1);
	}
}
void *consumer(void *arg)
{
	data_type _data;
	while(1)
	{
		pthread_mutex_lock(&lock);
		while(-1 == pop_node(head,&_data));
		{
			pthread_cond_wait(&cond,&lock);
		}
		printf("consumer data:%d\n",_data);
		pthread_mutex_unlock(&lock);
		sleep(1);
	}
}

int main()
{
        pthread_cond_t cond;
	pthread_cond_init(&cond,NULL);
	
	pthread_t tid1,tid2;
	pthread_create(&tid1,NULL,product,NULL);
	pthread_create(&tid2,NULL,consumer,NULL);
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	pthread_cond_destroy(&cond);
	return 0;
}


    //链表的更改:尾进 头出 

    ... ...
int pop_node(node_p list,data_type_p _data_p)
{
	if(list->next == NULL)
	{
		*_data_p=-1;
		return -1;
	}
	node_p tmp=list;
	list=list->next;
	delete_node(tmp);
	return 0;
}
void push_node(node_p list,data_type _data)
{
        node_p tmp=buy_node(_data);
	while(list->next)
	{
		list=list->next;
	}
	list->next=tmp;
	tmp->data=_data;
	tmp->next=NULL;
}
    ... ...


四、多生产者-消费者模型:

// 其余代码见上 
int main()
{
        pthread_cond_t cond;
	pthread_cond_init(&cond,NULL);
	
	pthread_t tid1,tid2,tid3,tid4;
	pthread_create(&tid1,NULL,product,NULL);
	pthread_create(&tid2,NULL,product,NULL);
	pthread_create(&tid3,NULL,consumer,NULL);
	pthread_create(&tid4,NULL,consumer,NULL);
	pthread_join(tid1,NULL);
	pthread_join(tid2,NULL);
	pthread_join(tid3,NULL);
	pthread_join(tid4,NULL);
	pthread_cond_destroy(&cond);
	return 0;
}

   注意 :生产者消费者问题,是同步和互斥的一个经典模型。但需要注意死锁问题,需要先同步再互斥。