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;
}

代码演示结果:

相关推荐
Scott9999HH1 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
Yana.nice2 小时前
Linux 只保留 30 天内日志(find命令删除日志文件)
linux·运维·chrome
码智社2 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海3 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖3 小时前
JDK 26 新特性详解
java·开发语言
马优晨4 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
DFT计算杂谈6 小时前
无 Root 权限在 Tesla K80 零门槛部署 DeepSeek 大模型
linux·服务器·网络·数据库·机器学习
人邮异步社区6 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大6 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai7 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang