首页/操作系统/进程管理/条件变量 🔗 在 Obsidian 中打开
操作系统 · 进程管理

条件变量

重要度 ★★★ 条件变量condition-variablewaitsignal
速查
条件变量是与互斥锁配合使用的同步机制:条件不满足时线程阻塞等待,条件满足时被唤醒。三操作:wait() 释放锁并阻塞 · signal() 唤醒一个 · broadcast() 唤醒全部

基本概念

条件变量是一种同步机制,允许线程在某个条件不满足时阻塞等待,并在条件满足时被唤醒。它本身不保存状态(信号可能丢失),必须和互斥锁(mutex)一起使用。

与管程条件变量是管程的组成部分,用于在管程内部实现进程/线程间的同步(如生产者-消费者、读者-写者)。

三个基本操作

  • wait(cv, mutex):释放 mutex,阻塞当前线程,等待条件 cv
  • signal(cv)(notify):唤醒一个在 cv 上等待的线程
  • broadcast(cv)(notifyAll):唤醒所有在 cv 上等待的线程
操作作用是否释放锁
wait(cv, mutex)阻塞等待条件成立释放 mutex
signal(cv)唤醒一个等待线程不释放 mutex
broadcast(cv)唤醒所有等待线程不释放 mutex
消费者线程while(!cond) 条件变量 cv无状态·可能丢信号 生产者线程设置条件→signal
点击上方按钮查看 wait / signal / broadcast 的行为

典型使用模式

// 等待方(消费者)
lock(mutex);
while (!condition) {    // 用 while,不用 if(防止虚假唤醒)
    wait(cv, mutex);    // 释放 mutex 并阻塞
}
// 处理数据
unlock(mutex);

// 通知方(生产者)
lock(mutex);
// 设置条件为 true
signal(cv);             // 唤醒一个等待线程
unlock(mutex);
关键点while 而非 if 检查条件——被唤醒后条件可能已被其他线程改变(虚假唤醒)。

易错点

必记
  1. wait() 先释放 mutex 再阻塞——不是先阻塞再释放(否则死锁)。
  2. 被唤醒后必须重新检查条件(while 不用 if),防止虚假唤醒。
  3. signal() 不释放 mutex——被唤醒线程需等 signal 线程释放锁后才能执行。
  4. 条件变量不保存状态——signal 时没有等待者,信号丢失。
  5. 信号量有计数(信号不丢失),条件变量没有(可能丢失)。

记忆卡片

三个操作?
wait() 阻塞等待、signal() 唤醒一个、broadcast() 唤醒全部。
wait() 为何释放 mutex?
不释放则其他线程无法修改条件,导致死锁。
为何用 while 不用 if?
防止虚假唤醒——被唤醒后条件可能已被其他线程改变。
条件变量 vs 信号量?
条件变量无状态(信号可丢失),信号量有状态(信号不丢失)。
signal() 释放 mutex 吗?
不释放——被唤醒线程等 signal 线程释放 mutex 后才能执行。
必须配合什么使用?
互斥锁(mutex),单独使用无意义。

交互动画 · 条件变量:生产者-消费者的 wait / signal

手动模式
生产者线程 加锁 → 生产 → 解锁count++ · 放入缓冲区 消费者线程 加锁 → 消费 → 解锁count-- · 取走产品 共享缓冲(互斥锁保护)count = 0 条件变量 not_empty / not_full 等待队列(阻塞线程)wait() 释放锁并入队 时序 t1 生产 t2 消费 t3 空等 t4 生产 t5 唤醒 t6 消费 关键:signal 只唤醒,被唤醒线程仍需重新获得锁并重新检查条件
while(条件不满足) cond.wait(&mutex); 生产/消费后 cond.signal(&mutex);
点击「播放」或「下一步」,观察 wait 释放锁阻塞、signal 唤醒的全过程
wait 与 signal 必须成对出现;signal 后仍用 while 检查条件防虚假唤醒
变量配色:生产者 · 消费者 · 共享计数 count,高亮即当前动作线程。

相关知识点

mutex-lock monitor

↑ 以上为站内 HTML 相对链接(纯网页可浏览);本页右上「在 Obsidian 中打开」跳回源笔记。