操作系统中的进程同步:条件变量(Condition Variable)详解
字数 1159 2025-11-26 08:38:04
操作系统中的进程同步:条件变量(Condition Variable)详解
1. 知识点描述
条件变量是一种进程/线程同步机制,用于在多个线程间实现复杂的等待/通知逻辑。它与互斥锁配合使用,主要解决"等待特定条件成立"的场景——当某个条件不满足时,线程自动释放锁并进入等待状态;当条件可能满足时,其他线程通过通知机制唤醒等待的线程。
2. 条件变量的核心作用
- 避免忙等待:线程在条件不满足时主动休眠,而不是循环检查消耗CPU
- 实现精准同步:只在条件真正满足时才唤醒相关线程
- 与互斥锁协同:保证对共享条件的检查与修改是原子性的
3. 条件变量的三个基本操作
3.1 等待(wait)操作
步骤:
1. 线程首先获取互斥锁(确保条件检查的原子性)
2. 检查条件是否满足
3. 如果条件不满足:
- 自动释放互斥锁(让其他线程能修改条件)
- 线程进入休眠状态(加入条件变量的等待队列)
4. 当被唤醒时:
- 重新获取互斥锁(保证后续操作的安全性)
- 再次检查条件(防止虚假唤醒)
3.2 通知(signal/broadcast)操作
signal(通知一个线程):
1. 线程获取互斥锁(保证修改条件的安全性)
2. 修改共享条件
3. 发送信号唤醒等待队列中的一个线程
4. 释放互斥锁
broadcast(通知所有线程):
1. 线程获取互斥锁
2. 修改共享条件
3. 发送信号唤醒等待队列中的所有线程
4. 释放互斥锁
4. 条件变量的典型使用模式
生产者-消费者场景示例:
// 共享资源
queue buffer;
mutex lock;
condition not_empty; // 缓冲区非空条件
condition not_full; // 缓冲区未满条件
// 生产者线程
void producer() {
lock.acquire();
while (buffer.is_full()) { // 必须用while循环检查
not_full.wait(&lock); // 等待"未满"条件
}
buffer.add(item);
not_empty.signal(); // 通知消费者"非空"
lock.release();
}
// 消费者线程
void consumer() {
lock.acquire();
while (buffer.is_empty()) { // 必须用while循环检查
not_empty.wait(&lock); // 等待"非空"条件
}
item = buffer.remove();
not_full.signal(); // 通知生产者"未满"
lock.release();
}
5. 关键实现细节
5.1 为什么需要while循环而不是if?
- 虚假唤醒:某些实现中线程可能在没有收到通知时被意外唤醒
- 条件可能再次改变:被唤醒后条件可能已被其他线程修改
- 广播唤醒:使用broadcast时多个线程被唤醒,但条件可能只满足一个
5.2 条件变量与互斥锁的关系
- 条件变量本身不提供互斥保护,必须与互斥锁配合使用
- wait操作会自动释放锁,唤醒后会自动重新获取锁
- 这种"释放锁-等待-重新获取锁"的原子性由条件变量保证
6. 条件变量的底层实现机制
6.1 等待队列管理
- 每个条件变量维护一个等待队列
- wait操作将当前线程加入队列并设置休眠状态
- signal/broadcast操作从队列中移除线程并设置为就绪状态
6.2 与调度器的交互
wait操作:
- 将线程状态从RUNNING改为WAITING
- 将线程加入条件变量的等待队列
- 调用调度器切换线程
signal操作:
- 从等待队列中移出线程
- 将线程状态从WAITING改为READY
- 将线程加入就绪队列
7. 条件变量的常见问题与解决方案
7.1 丢失唤醒问题
- 场景:通知发生在等待之前,导致通知被丢失
- 解决:始终在持有锁的情况下修改条件和发送通知
7.2 优先级反转问题
- 场景:低优先级线程持有锁,高优先级线程在条件变量上等待
- 解决:使用优先级继承或优先级天花板协议
8. 不同操作系统中的实现差异
8.1 POSIX条件变量(pthread_cond_t)
pthread_cond_wait()、pthread_cond_signal()、pthread_cond_broadcast()- 需要与
pthread_mutex_t配合使用
8.2 Windows条件变量(CONDITION_VARIABLE)
SleepConditionVariableCS()、WakeConditionVariable()、WakeAllConditionVariable()- 可与临界区或SRW锁一起使用
条件变量是构建高级同步原语(如阻塞队列、读写锁等)的基础组件,正确理解其原理和使用模式对编写可靠的多线程程序至关重要。