621 字
3 分钟
条件变量是什么?为什么要和互斥锁配合使用
条件变量让线程等待某个共享状态谓词成立,例如“队列非空”或“任务已完成”。它本身不保存业务数据,也不等同于事件计数器;状态通常放在共享变量中,互斥锁保护该状态,条件变量负责让等待者在谓词不成立时睡眠,并在状态可能改变时唤醒。
典型流程是:线程先持有互斥锁,循环检查谓词;若不成立,调用条件等待。等待操作会原子地释放互斥锁并进入等待;被唤醒后重新取得互斥锁,再次检查谓词,只有条件确实成立才继续。修改状态的线程也应持锁更新谓词,再通知一个或多个等待者。
等待必须使用 while 而非 if。原因包括虚假唤醒、多个消费者被同时唤醒但只有一个能取到任务,以及通知发出时条件稍后又被其他线程改变。通知不是“条件为真”的证明;共享谓词才是事实来源。通常先更新状态再通知,这样等待者醒来后能观察到新状态。
如果等待者检查谓词、释放锁、进入等待这几步不是协调好的,通知可能恰好发生在检查之后、睡眠之前,造成丢失唤醒。条件等待与锁配合的原子释放/等待过程正是为了避免这个窗口。超时等待还要检查最终谓词,不能把超时或被唤醒直接当作任务完成。
常见追问
Q:为什么条件变量一定要配互斥锁?
A:锁保护谓词状态,并使“检查状态、释放锁并等待”与通知方修改状态之间建立正确协调,避免检查和睡眠之间丢失通知。
Q:notify 一次代表一定有一个线程继续吗?
A:不保证。可能没有等待者,通知不会替未来等待者保存一个许可;也可能唤醒后条件已被其他线程消费。需要持续检查谓词。
Q:什么时候用信号量,什么时候用条件变量?
A:信号量适合对许可数量计数;条件变量适合等待任意共享状态谓词,并与互斥锁配合。条件变量通知通常不累计,不能简单互换。
条件变量是什么?为什么要和互斥锁配合使用
https://blog.xqcherry.top/posts/interview/operating-system/condition-variable/ 目录