Linux 线程同步——条件变量

一、条件变量的概念

如果说互斥锁是用于同步线程对共享数据的访问的话,那么条件变量则是用于在线程之间同步共享数据的值。条件变量提供了一种线程间的通知机制:当某个共享数据达到某个值的时候,唤醒等待这个共享数据的线程。如下图所示:

二、条件变量相关函数

1.pthread_cond_init()初始化条件变量

参数解释:

第一个参数cond:条件变量

第二个参数attr:条件变量属性,通常传NULL,表示使用默认属性

2.pthread_cond_wait()等待条件变量满足

功能:阻塞等待一个条件变量(等待唤醒)并解除相应的锁资源

参数解释:

第一个参数cond:条件变量

第二个参数mutex:是用于保护条件变量的互斥锁,以确保pthread_cond_wait操作的原子性。在调用pthread_cond_wait之前必须确保互斥锁mutex已经加锁,否则将会出现多个线程同时要进入等待队列的情况导致不可预期的结果。pthread_cond_wait在执行时,首先把调用线程放入条件变量的等待队列中,然后将互斥锁解锁。从pthread_cond_wait开始执行到其调用线程被放入条件变量的等待队列之间的这段时间内,pthread_cond_signal和pthread_cond_broadcast等函数不会修改条件变量的值。也就是说,当线程在进出条件变量的等待队列的时候是不会去唤醒等待队列中的其他线程的。当pthread_cond_wait函数成功返回时,互斥锁mutex将再次被锁上,这是pthread_cond_wait函数内部做的事情,就是为了防止在唤醒某个线程的时候和其他线程进出等待队列发生冲突。如果有一个线程正在进入等待队列,这时想要唤醒某个线程时就需要加锁,就会加锁失败,要等正在进入等待队列的线程彻底进去之后解锁,然后才能加锁去唤醒想要唤醒的线程,然后再加锁,然后出等待队列的之后在进行解锁。

注意:

线程被唤醒,pthread_cond_wait函数返回时,解除阻塞并重新申请获取互斥锁。

3.pthread_cond_broadcast()唤醒全部在等待条件变量的线程

参数解释:

参数cond:条件变量

4.pthread_cond_signal()唤醒一个在等待条件变量的线程(随机唤醒一个)

参数解释:

参数cond:条件变量

5.pthread_cond_destroy()销毁条件变量

参数解释:

参数cond:条件变量

三、条件变量的使用

【例】有两个线程A和B在等待队列中,给一个数组buff,当从键盘上向buff中写入数据之后,就随机唤醒一个线程去读取buff中的内容并输出,当从键盘上向buff中写入"end"的时候,唤醒所有正在等待的线程,让所有线程退出。

上例中,条件变量就是用户从键盘输入的数据,线程A和线程B根据条件变量的情况被唤醒。

代码如下 :

c 复制代码
#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<pthread.h>
#include<string.h>
#include<semaphore.h>

pthread_cond_t cond;
pthread_mutex_t mutex;

char buff[128]={0};

void* fun_a(void* arg)
{
    while(1)
    {
        //在线程A进入等待队列之前加锁,如果加锁成功,线程A进入等待队列,这时别的线程不可以进入等待队列
        pthread_mutex_lock(&mutex);

        //线程A进入等待队列中,线程B被阻塞,解锁,线程A被唤醒,加锁
        pthread_cond_wait(&cond,&mutex);

        //在线程A从等待队列出来之后,解锁,这时别的线程就可以进入等待队列
        pthread_mutex_unlock(&mutex);
        if(strncmp(buff,"end",3)==0)        
        {
            break;
        }
        else
        {
            printf("线程A输出:%s",buff);
        }

    }
    printf("线程A结束\n");
}

void* fun_b(void* arg)
{
    while(1)
    {
        //在线程B进入等待队列之前加锁,如果加锁成功,线程B进入等待队列,这时别的线程不可以进入等待队列
        pthread_mutex_lock(&mutex);

        //线程B进入等待队列中,线程B被阻塞,解锁,线程B被唤醒,加锁
        pthread_cond_wait(&cond,&mutex);

        //在线程B从等待队列出来之后,解锁,这时别的线程就可以进入等待队列
        pthread_mutex_unlock(&mutex);

        if(strncmp(buff,"end",3)==0)
        {
            break;
        }
        else
        {
            printf("线程B输出:%s",buff);
        }
    }
    printf("线程B结束\n");
}

int main()
{
    pthread_mutex_init(&mutex,NULL);
    pthread_cond_init(&cond,NULL);

    pthread_t id1,id2;
    pthread_create(&id1,NULL,fun_a,NULL);
    pthread_create(&id2,NULL,fun_b,NULL);

    while(1)
    {
        
        fgets(buff,128,stdin);

        if(strncmp(buff,"end",3)==0)
        {
            //唤醒所有
            pthread_cond_broadcast(&cond);
            break;
        }
        else
        {
            //随机唤醒一个
            pthread_cond_signal(&cond);
        }
    }

    pthread_join(id1,NULL);
    pthread_join(id2,NULL);

    pthread_mutex_destroy(&mutex);
    pthread_cond_destroy(&cond);

    exit(0);
}

运行结果:

相关推荐
IT学长编程7 分钟前
计算机毕业设计 Java酷听音乐系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·课程设计·毕业论文·音乐系统·计算机毕业设计选题
cuisidong199716 分钟前
如何在 Kali Linux 上安装 Google Chrome 浏览器
linux·运维·chrome
IT学长编程24 分钟前
计算机毕业设计 基于协同过滤算法的个性化音乐推荐系统的设计与实现 Java实战项目 附源码+文档+视频讲解
java·spring boot·毕业设计·毕业论文·协同过滤算法·计算机毕业设计选题·个性化音乐推荐系统
小小娥子29 分钟前
Redis的基础认识与在ubuntu上的安装教程
java·数据库·redis·缓存
几何心凉37 分钟前
已解决:org.springframework.web.HttpMediaTypeNotAcceptableException
java
华农第一蒟蒻39 分钟前
Java中JWT(JSON Web Token)的运用
java·前端·spring boot·json·token
两点王爷41 分钟前
使用WebClient 快速发起请求(不使用WebClientUtils工具类)
java·网络
光通信学徒1 小时前
ubuntu图形界面右上角网络图标找回解决办法
linux·服务器·ubuntu·信息与通信·模块测试
计算机学姐1 小时前
基于SpringBoot+Vue的高校运动会管理系统
java·vue.js·spring boot·后端·mysql·intellij-idea·mybatis
wusam1 小时前
螺蛳壳里做道场:老破机搭建的私人数据中心---Centos下Docker学习03(网络及IP规划)
运维·服务器·网络·docker·容器