Linux条件变量

在 Linux 系统中,pthread_cond_init() 函数和条件变量(Condition Variable)是多线程编程中用于线程同步的核心机制。它们通过协调线程间的等待与通知逻辑,解决共享资源的竞争问题。以下从功能、工作机制、使用场景和注意事项等方面进行详细解析:

一、条件变量的核心概念

条件变量是一种线程同步原语,允许线程在某个条件未满足时进入阻塞状态,并在条件满足时被唤醒。其核心作用包括:

  1. ​等待条件​ :线程通过 pthread_cond_wait() 释放互斥锁并阻塞,直到其他线程发送信号。
  2. ​通知条件​ :其他线程通过 pthread_cond_signal()pthread_cond_broadcast() 触发条件变量,唤醒等待的线程。
  3. ​与互斥锁配合​ :条件变量必须与互斥锁(pthread_mutex_t)结合使用,避免竞争条件(Race Condition)。

二、pthread_cond_init() 函数的作用

pthread_cond_init() 用于动态初始化条件变量,其原型为:

cpp 复制代码
int pthread_cond_init(pthread_cond_t *cond, const pthread_condattr_t *attr);
  • ​参数​
    • cond:指向条件变量的指针。
    • attr:条件变量属性(通常设为 NULL,使用默认属性)。
  • ​返回值​ :成功返回 0,失败返回错误码(如 EINVALEBUSY)。
  • ​初始化方式​
    • ​静态初始化​ :直接赋值宏 PTHREAD_COND_INITIALIZER,适用于全局或静态变量。
    • ​动态初始化​ :通过 pthread_cond_init() 动态创建,适用于需要自定义属性的场景(如进程间共享。

三、条件变量的工作机制

1. 线程等待条件(pthread_cond_wait
  • ​步骤​
    1. 线程持有互斥锁,检查条件是否满足。
    2. 若条件不满足,调用 pthread_cond_wait() 释放互斥锁并阻塞。
    3. 被唤醒后,重新获取互斥锁并再次检查条件。
  • ​关键特性​
    • ​原子性​:释放锁和阻塞操作是原子的,避免竞争条件。
    • ​虚假唤醒​ :线程可能因系统信号意外唤醒,需用 while 循环而非 if 检查条件。
2. 线程发送信号(pthread_cond_signal/pthread_cond_broadcast
  • pthread_cond_signal:唤醒一个等待线程(若有多个线程等待,具体唤醒哪个由调度策略决定)。
cpp 复制代码
int pthread_cond_signal(pthread_cond_t *cond);
  • pthread_cond_broadcast:唤醒所有等待线程,适用于需要批量通知的场景(如生产者-消费者模型)
cpp 复制代码
int pthread_cond_broadcast(pthread_cond_t *cond);
​特性​ pthread_cond_signal() pthread_cond_broadcast()
​唤醒线程数量​ 至少 1 个(可能更多,但规范未定义) 所有等待线程
​适用场景​ 单任务处理(如单资源可用) 批量任务处理(如多资源可用)
​性能开销​ 较低(仅唤醒一个线程) 较高(需处理多线程竞争锁)
​虚假唤醒风险​ 需通过 while 循环检查条件 同样需 while 循环检查条件
​调度确定性​ 可能因优先级或系统策略影响唤醒顺序 无确定性,所有线程均被唤醒

代码演示:

cpp 复制代码
#include<iostream>
#include<pthread.h>
#include<unistd.h>
#include<string>

const int num = 5;
pthread_mutex_t gmutex = PTHREAD_MUTEX_INITIALIZER;             //全局锁
pthread_cond_t gcond = PTHREAD_COND_INITIALIZER;               //全局条件变量
void* wait(void*args)                                          //线程回调函数
{
    while(true)
    {
        //加锁
        pthread_mutex_lock(&gmutex);
        //条件变量,线程在这里阻塞等待
        pthread_cond_wait(&gcond,&gmutex);

        std::string name = static_cast<const char*>(args);
        usleep(10000); 
        std::cout<<"I am :"<<name<<std::endl;          
        //解锁
        pthread_mutex_unlock(&gmutex);
    }
    return nullptr;
}

int main()
{
    pthread_t threads[num];                                     //设置线程
    for(int i=0;i<num;i++)                                      //创建5个线程
    {
        char*name = new char[1024];                             //线程名称
        snprintf(name,1024,"thread-%d",i+1);
        pthread_create(threads+i,nullptr,wait,(void*)name);     //创建线程
        usleep(10000);                                          //设置创建线程和条件变量阻塞等待为同一时间
    }
    
    //主线程唤醒阻塞等待
    while(true)
    {
        pthread_cond_signal(&gcond);                             //唤醒一个线程
        std::cout<<"唤醒一个线程..."<<std::endl;
        sleep(2);
    }
    
    for(int i=0;i<num;i++)
    {
        pthread_join(threads[i],nullptr);                         //回收
    }
    return 0;
}

代码演示结果:

相关推荐
君的名字26 分钟前
怎么判断一个Android APP使用了Qt 这个跨端框架
android·开发语言·qt
酷道35 分钟前
CentOS停止维护了,解决yum不能安装软件的问题
linux·运维·centos
不秃的开发媛35 分钟前
JFace中MVC的表的单元格编辑功能的实现
java·开发语言·mvc
摆烂仙君41 分钟前
怎样通过神经网络估计股票走向
linux·运维·服务器
努力学习的小廉43 分钟前
我爱学算法之—— 二分查找(中)
开发语言·c++·算法
咸鱼2333号程序员1 小时前
Linux 输出输入重定向、tee命令详解
linux·运维·服务器·shell编程
只_只1 小时前
A1012 PAT甲级JAVA题解 The Best Bank
开发语言·python
fashia1 小时前
Java转Go日记(五十六):gin 渲染
开发语言·后端·golang·go·gin
敷啊敷衍1 小时前
C++ vector 深度解析:从原理到实战的全方位指南
开发语言·c++·算法
o0向阳而生0o1 小时前
48、c# 中 IList 接⼝与List的区别是什么?
开发语言·c#·list·.net