Linux--线程同步与互斥之条件变量

来源:互联网 发布:监控软件大全 编辑:程序博客网 时间:2024/04/27 21:39

上篇博客讲了互斥量问题:http://blog.csdn.net/sayhello_world/article/details/67637858

 

就拿生产者-消费者为例,如果两个线程都有互斥锁,但是生产者生产的快,消费者消费的慢,这里我们会发现,消费者一直再消费此时生产者还没有产生东西。这就会导致消费者总是加锁进来再解锁出去。为了让两者同步,这里提出了条件变量。

 

条件变量是线程可用的另一种同步机制。互斥量用于上锁,条件变量则用于等待,并且条件变量总是需要与互斥量一起使用。

 

需要了解的函数:

初始化函数:

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_wait(pthread_cond_t*restrict cond, pthread_mutex_t *restrict mutex);

 

信号函数:

int pthread_cond_signal(pthread_cond_t*cond);

 

销毁函数:

int pthread_cond_destroy(pthread_cond_t*cond);

 

和Mutex的初始化和销毁类似,pthread_cond_init 函数初始化为Condition Variable,attr参数为NULL则表示缺省属性,pthread_cond_destroy函数销毁一个Condition Variable。如果ConditionVariable是静态分配的,也可以用宏定义PTHEAD_COND_INITIALIZER初始化,相当于 用pthread_cond_init函数初始化并且attr参数为NULL。

 

一个线程可以调用pthread_cond_wait在一个ConditionVariable上阻塞等待,这个函数做以下三步操作:

1. 释放Mutex

2. 阻塞等待

3. 当被唤醒时,重新获得Mutex并返回

 

基于此 我们实现生产者-消费者模式。

代码思想说明:

生产者生产数据插入链表 消费者从链表中读取数据,中间场所为链表。

当消费者读取数据的时候 他需要加锁解锁并且要等待生产者生产数据。

当生产者写入数据的时候 他应该向链表中插入元素并且给消费者一个信号。

 

321模型:

3种关系:生产者--- 生产者,消费者--- 消费者,生产者--- 消费者

2种角色:生产者,消费者

1种交易场所:链表


代码实现:

#include<stdio.h>#include<stdlib.h>#include<unistd.h>#include<assert.h>#include<pthread.h>typedef struct plist{        struct plist* next;        int data;}node_t,*node_p,**node_pp;static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;static node_p malloc_node(int d){        node_p _n = (node_p)malloc(sizeof(node_t));        if(_n == NULL)        {           perror("malloc\n");           exit(1);        }          _n -> data = d;          _n -> next = NULL;        return _n;} static is_empty(node_p p){        return p->next == NULL?1:0;}static delete_node(node_p p){        if(p != NULL)        {          free(p);        }}void init_list(node_pp p){        *p = malloc_node(0);}//头插void push_list(node_p p,int data){        node_p cur = malloc_node(data);        cur ->next = p->next;        p->next = cur;}//头删void pop_list(node_p p,int *d){        assert(p);        assert(d);        if(!is_empty(p))        {          node_p temp = p->next;          p->next = temp->next;          *d = temp->data;          delete_node(temp);        }}//销毁链表void destroy_list(node_p p){        assert(p);        int data;        while(!is_empty(p))        {                pop_list(p,&data);        }        delete_node(p);}void show_list(node_p p){        assert(p);        while(p != NULL)        {          printf("%d  ",p->data);          p = p->next;        }        printf("\n");}static void *consumer(void *arg){        node_p phead = (node_p)arg;        int data = 0;        for(;;)        {          pthread_mutex_lock(&lock);          //当链表为空的时候,消费者应该等待生产者。          while(is_empty(phead))          {            printf("consumer no data\n");            pthread_cond_wait(&cond,&lock);          }          pop_list(phead,&data);          printf("consumer done:....%d\n",data);          pthread_mutex_unlock(&lock);        }        return NULL;}static void *produce(void *arg){        node_p phead = (node_p)arg;        int data = 0;        for(;;)        {          pthread_mutex_lock(&lock);          data = rand()%1234;          push_list(phead,data);          printf("produce data %d\n",data);          pthread_mutex_unlock(&lock);          //这里的sleep是为了让两者不同步,一个快一个慢。          sleep(1);          pthread_cond_signal(&cond);          printf("call consumer. preduce success val = %d\n",data);        }        return NULL;}int main(){        node_p phead = NULL;        init_list(&phead);        pthread_t p_produce;        pthread_t p_consumer;        pthread_create(&p_consumer,NULL,consumer,phead);        pthread_create(&p_produce,NULL,produce,phead);        pthread_join(p_consumer,NULL);        pthread_join(p_produce,NULL);        pthread_mutex_destroy(&lock);        pthread_cond_destroy(&cond);        destroy_list(phead);        return 0;}

结果两者实现同步:


1 0
原创粉丝点击