一、生产者-消费者问题:
同步和互斥是进程间很重要的交互模式,而生产者和消费者问题则是同步和互斥的一个经典模型。
同步是一种时序关系。如规定了进程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;
}
注意 :生产者消费者问题,是同步和互斥的一个经典模型。但需要注意死锁问题,需要先同步再互斥。
转载于:https://blog.51cto.com/zxtong/1766832