Linux:多线程-条件变量

条件变量

条件变量在多线程编程中,提供了线程等待-唤醒的逻辑模式。通过用户自己的条件判断去设置什么时候让线程进行等待,什么时候进行唤醒。
本质:线程等待队列+等待与唤醒接口

通过一个关于生产和消费的模型理解条件变量

//通过生产者和消费者,来体会对临界资源的访问时序性和对条件变量的使用
//本程序想要得到的效果是,保证两个线程执行的时序性。
//循环生产一个资源后再去消费一个资源。
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <pthread.h>
//定义生产者和消费者条件变量,其实可以理解为定义了两个等待队列
pthread_cond_t _con;
pthread_cond_t _pro;

//定义互斥锁
pthread_mutex_t _mutex;

//初始化资源数量为0
int is_hava_resource = 0;

//声明两个线程执行函数
void *thr_con(void *arg);
void *thr_pro(void *arg);
int main()
{
    //1.分别创建一个生产者线程和消费者线程
    //2.分别设置线程执行函数,一个进行消耗资源,一个负责生产资源
    
    //条件变量和互斥锁的初始化
    pthread_cond_init(&_con,NULL);
    pthread_cond_init(&_pro,NULL);
    pthread_mutex_init(&_mutex,NULL);
    
    pthread_t con_tid;
    pthread_t pro_tid;
    int ret;
    ret = pthread_create(&con_tid,NULL,thr_con,NULL);
    if(ret != 0)
    {
        perror("create error\n");
        return -1;
    }
    ret = pthread_create(&pro_tid,NULL,thr_pro,NULL);
    if(ret != 0)
    {
        perror("create error\n");
        return -1;
    }
    pthread_join(con_tid,NULL);
    pthread_join(pro_tid,NULL);

	//条件变量和互斥锁的销毁
    pthread_cond_destroy(&_con);
    pthread_cond_destroy(&_pro);
    pthread_mutex_destroy(&_mutex);
    return 0;
}
void *thr_con(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&_mutex);
        while(is_hava_resource == 0)
        {
            pthread_cond_wait(&_con,&_mutex);//让消费者进行等待
        }
        is_hava_resource--;
        printf("i get a resource\n");
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_pro);//唤醒生产者进行生产
    }
}
void *thr_pro(void *arg)
{
    while(1)
    {
        pthread_mutex_lock(&_mutex);
        while(is_hava_resource == 1)
        {
            pthread_cond_wait(&_pro,&_mutex);//让生产者进行等待
        }
        is_hava_resource++;
        printf("i make a resource\n");
        pthread_mutex_unlock(&_mutex);
        pthread_cond_signal(&_con);//唤醒消费者进行消耗
    }
}



执行结果:
达到了预期效果

条件变量使用需要理解的难点

一、为什么条件变量要搭配互斥锁使用

1.首先了解,pthread_wait封装了三个操作。
	一、解锁
	二、将其置入等待队列,阻塞,直到被唤醒。
	三、上锁
	其中步骤一和步骤二是原子操作。因为有上锁和解锁操作,所以要搭配互斥锁。

二、在进行条件判断的时候必须使用while而不能使用if

pthread_cond_signal是至少唤醒一个线程。若唤醒两个及以上的线程,
当第一个线程上锁后,其他线程就阻塞在上锁这一步操作了,
第一个线程在执行操作后会进行解锁,此时其他的线程就会继续向下运行,
但此时并没有资源可以使用。
因此,必须使用while再次判断,保证不会造成没有资源还对资源访问的操作。
可以根据下面图片理解

在这里插入图片描述

三、不同类型的线程为何需要不同的条件变量

这个例子还暴露不出这个问题。
上面说到pthread_cond_signal()在唤醒的时候,不是单一唤醒,是至少唤醒一个。
因此,若一个队列上有不同类型的线程,所有的线程可能都被唤醒,这不就不符合我们让其什么时候什么时候唤醒的逻辑了吗。
发布了35 篇原创文章 · 获赞 13 · 访问量 2113

猜你喜欢

转载自blog.csdn.net/weixin_42458272/article/details/103302029