Linux条件变量的使用

目录

1. 条件变量的原理

2.条件变量常用的函数

3.生产者和消费者模型

4.示例:


1. 条件变量的原理

条件变量不是锁,但是条件变量可以阻塞线程,一般将条件变量和互斥锁共同使用,其中互斥锁是为了保护一块区域,条件变量则是用于阻塞线程。一般条件变量的工作方式可以概括为2步

(1)条件不满足,阻塞线程。

(2)条件满足时,通知线程开始工作

2.条件变量常用的函数

1.定义条件变量
pthread_cond_t cond;

2.初始化条件变量
pthread_cond_init(
    pthread_cond_t *restrict cond;
    const pthread_condattr_t *restrict attr;
);
示例:
pthread_cond_init(&cond, NULL);   			动态初始化。
pthread_cond_t cond = PTHREAD_COND_INITIALIZER;	静态初始化。

3. 销毁条件变量
pthread_cond_destory(pthread_cond_t *cond);

4.阻塞一个条件变量
pthread_cond_wait(
    pthread_cond_t *restrict cond,
    pthread_mutex_t *restrict mutex
);
介绍:
    1) 阻塞等待条件变量满足
    2) 解锁已经加锁成功的信号量 (相当于 pthread_mutex_unlock(&mutex)),12两步为一个原子操作
    3)  当条件满足,函数返回时,解除阻塞并重新申请获取互斥锁。重新加锁信号量 (相当于,         
        pthread_mutex_lock(&mutex))

5.限时等待一个条件变量
pthread_cond_timewait(
    pthread_cond_t *restrict cond,
    pthread_mutex_t *restrict mutex,
    const struct timespec *restrict abstime
);

6.唤醒阻塞线程
唤醒一个阻塞线程
pthread_cond_signal(ptread_cond_t *cond);
唤醒全部阻塞线程
pthread_cond_broadcast(pthread_cond_t *cond);

3.生产者和消费者模型

本节将通过生成者和消费者模型来总结条件变量的使用过, 模型分析:

生产者:生产数据,加锁数据,将数据写入公共区域,解锁,通知阻塞在条件变量上线程,最后继续生产数据
消费者:创建锁,初始化,加锁,等待条件满足,访问共享数据,解锁,释放条件变量和锁。

    

4.示例:

代码实现链表的头插法插入

头插法过程分析

       

         

代码分析 

#include <stdio.h>  
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <errno.h>  
#include <pthread.h> 

void err_thread(int ret, char *str)  
{  
    if (ret != 0) {  
        fprintf(stderr, "%s:%s\n", str, strerror(ret)); 
        pthread_exit(NULL);  
    }  
}  


/*链表作为公享数据,需被互斥量保护*/
struct msg {  
    struct msg *next;  
    int num;  
};  

/*头结点*/
struct msg *head;

/*静态初始化,条件变量和一个互斥锁*/
pthread_cond_t has_product = PTHREAD_COND_INITIALIZER;
pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;

/*消费者*/
void *consumer(void *p)
{

    
    /*消费者循环消费, 创建和初始化已经在开始,静态定义*/
    while(1)
    {
        struct msg *mp;    
    
         /*3. 上锁*/
        pthread_mutex_lock(&lock)

        /*头结点为空,没有结点解锁,解锁并阻塞等待*/
        /*4. 条件满足,处理数据,条件不满足阻塞数据*/
        while(head == NULL)
        {
            /*解锁并阻塞等待*/
            pthread_cond_wait(&has_product, &lock);
        }

        /*5. 访问共享数据*/
        mp = head;        
        head = mp->next;                 //模拟消费掉一个产品 

        /*6. 解锁,释放条件变量,释放锁*/ 
        pthread_mutex_unlock(&lock);  
 
        printf("-Consume %lu---%d\n", pthread_self(), mp->num);  
        free(mp);  
        sleep(rand() % 5);   
    } 

    return NULL; 
}

/*生产者*/
void *producer(void *arg)
{
    /*定义结构体变量*/
    while(1)
    {
        struct msg *mp = malloc(sizeof(struct msg));       
        
         /*1.生产数据*/
        mp -> num = rand() %1000 + 1;
        printf("-Produce %d\n", mp->num);
        /*头插法实现链表插入:生产的即为插入的结点*/
        
        /*2.加锁*/
        pthread_mutex_lock(&lock);

        /*3. 将数据发到公共区域,头插法加入链表*/
        mp->next = head;  
        head = mp;

        /*4. 解锁*/
        pthread_mutex_unlock(&lock);

        /*5. 通知唤醒阻塞在条件变量上的线程*/ 
        pthread_cond_signal(&has_product);

        sleep(rand() % 5);  
    }
    return NULL;
}

int main(int argc, char *argv[])  
{  
    int ret;
    pthread_t pid, cid;  
    srand(time(NULL));  
  
    /*创建两个线程分别作为生产者和消费者*/
    ret = pthread_create(&pid, NULL, producer, NULL); 
	if (ret != 0)   
	    err_thread(ret, "pthread_create produser error");

    ret = pthread_create(&cid, NULL, consumer, NULL);
    if(ret != 0)
	    err_thread(ret, "pthread_create produser error");
 
  
    /*释放两个线程*/
    pthread_join(pid, NULL);  
    pthread_join(cid, NULL);  
  
    return 0;  
}

结果:

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值