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,失败返回错误码(如 EINVAL、EBUSY)。
  • ​初始化方式​ :
    • ​静态初始化​ :直接赋值宏 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;
}

代码演示结果:

相关推荐
Fcy6486 分钟前
Linux下 五种IO模型的认识与⾮阻塞IO的实现
linux·服务器·io
geats人山人海19 分钟前
java 4继承
java·开发语言
Mikko731 分钟前
Linux 重启后日志没了?进程被 OOM 杀了去哪看?logrotate 之后日志还往旧文件写?三台真机实测日志与性能排查
linux·运维·centos
aqiu11111131 分钟前
【C++算法打怪专栏】C++ `unordered_set` 常用初始化与插入方法总结
开发语言·c++·算法
书生执笔画浮沉34 分钟前
分享一个开源小工具CAdapt
linux·c·gnu·glibc·kernel·升级·灵感
众链网络42 分钟前
Agent 的成本大头不在“写“,在“判断“:拆解专用决策模型的三层架构
java·开发语言·人工智能·微服务
周小董1 小时前
[1371]jdk管理工具
java·开发语言
Terra.K1 小时前
高精度阶乘求和模板深度解析
开发语言·c++·算法
Hum8le1 小时前
漏洞知识点《php伪协议》
开发语言·安全·web安全·php
青春逝如流水1 小时前
Java 中线程的创建方式:从基础到现代
java·开发语言·多线程·ai文章