同一condition variable能否搭配不同mutex使用?
关于std::condition_variable notify_one()文档的疑问澄清
你对文档原文的理解存在核心偏差,那段说明的前置默认条件是所有线程操作共享同一个mutex,绝非允许通知线程和等待线程使用不同的mutex。
文档原文的准确解读
你看到的这段说明:
执行通知的线程无需持有与等待线程所持有的相同mutex上的锁;实际上这样做属于优化劣化,因为被通知的线程会立刻再次阻塞,等待通知线程释放锁。
它的实际含义是:调用notify_one()发通知的这个时间点,不需要再持有所有线程共享的那个mutex的锁,仅此而已,完全没有「可以用不同mutex」的语义。
条件变量的强制使用规则
条件变量的使用有不可突破的约束,违反就会触发未定义行为:
- 所有等待该条件变量的线程,以及所有修改该条件变量关联的判断谓词(比如示例中的
ready、processed)的线程,必须使用同一个mutex做同步 - 等待线程调用
wait()时传入的锁,必须是已经持有该共享mutex的std::unique_lock实例
你理解的「用不同mutex会让mutex失去意义」完全正确,网传的「用独立局部mutex更好」的说法没有任何依据,属于错误引导。如果使用不同mutex,会直接出现数据竞争、通知丢失、虚假唤醒无法被过滤等问题。
通知时不需要持锁的原因
notify_one()的作用只是唤醒正在等待的线程,本身不需要访问共享的状态变量,因此不需要加锁保护。
如果在持有锁的状态下调用notify_one():被唤醒的线程从wait调用中返回前,必须先获取到关联的mutex锁,而此时锁还被通知线程持有,被唤醒的线程会立刻再次进入阻塞状态,直到通知线程释放锁,这个过程多了一次无意义的上下文切换,平白增加了开销,因此属于优化劣化。
关于通知线程是否需要加锁的澄清
通知线程绝对不是完全不需要加锁,只是加锁的时机不是发通知的时候:
- 加锁是为了保护共享状态(谓词变量、业务数据)的修改,避免数据竞争
- mutex的同步语义保证了修改后的共享变量对被唤醒的线程可见
正确的执行顺序是:
- 通知线程加锁,修改共享谓词变量
- 通知线程释放锁
- 通知线程调用
notify_one()发送通知
你给出的cppreference示例代码完全符合这个最优执行顺序。
内容的提问来源于stack exchange,提问作者speed_of_light
相关产品推荐
相关产品推荐

