在 Linux 系统中,pthread_cond_init()
函数和条件变量(Condition Variable)是多线程编程中用于线程同步的核心机制。它们通过协调线程间的等待与通知逻辑,解决共享资源的竞争问题。以下从功能、工作机制、使用场景和注意事项等方面进行详细解析:
一、条件变量的核心概念
条件变量是一种线程同步原语,允许线程在某个条件未满足时进入阻塞状态,并在条件满足时被唤醒。其核心作用包括:
- 等待条件 :线程通过
pthread_cond_wait()
释放互斥锁并阻塞,直到其他线程发送信号。 - 通知条件 :其他线程通过
pthread_cond_signal()
或pthread_cond_broadcast()
触发条件变量,唤醒等待的线程。 - 与互斥锁配合 :条件变量必须与互斥锁(
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
)
- 步骤 :
- 线程持有互斥锁,检查条件是否满足。
- 若条件不满足,调用
pthread_cond_wait()
释放互斥锁并阻塞。 - 被唤醒后,重新获取互斥锁并再次检查条件。
- 关键特性 :
- 原子性:释放锁和阻塞操作是原子的,避免竞争条件。
- 虚假唤醒 :线程可能因系统信号意外唤醒,需用
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;
}
代码演示结果:
