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

代码演示结果:

相关推荐
明天见~~7 分钟前
Linux下的网络编程
linux·运维·网络
NEXU58 分钟前
Linux:网络层IP协议
linux·网络·tcp/ip
Aczone288 分钟前
Linux 软件编程(九)网络编程:IP、端口与 UDP 套接字
linux·网络·网络协议·tcp/ip·http·c#
倔强的石头_21 分钟前
【Linux指南】Makefile入门:从概念到基础语法
linux
Code_Dragon36 分钟前
最近遇到的bug
linux·前端
武文斌7740 分钟前
计算机网络:网络基础、TCP编程
linux·网络·网络协议·tcp/ip·计算机网络
草莓熊Lotso1 小时前
【C++】--函数参数传递:传值与传引用的深度解析
c语言·开发语言·c++·其他·算法
Ice__Cai1 小时前
Flask 路由详解:构建灵活的 URL 映射系统
开发语言·python·flask
EnigmaCoder1 小时前
【Linux】Vim编辑器:从入门到高效使用
linux·运维·编辑器·vim
l1t1 小时前
分析xml标签属性和压缩级别对xlsx文件读取解析的影响
xml·开发语言·python·sql·duckdb