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

上篇博客讲了互斥量问题: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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值