C++提供了两个条件变量的实现:std::condition_variable
和 std::condition_variable_any
,这两个都在 <condition_variable>
库的头文件中声明。两者都需要和互斥元一起工作,前者仅限于 std::mutex
,后者可以与符合称为类似互斥元的最低标准的任何东西一起工作,因此跟普遍,所以会有大小、性能或者操作系统资源方面的形式的额外代价的可能。
1 | std::mutex mut; |
当来自数据准备线程中对 notify_one()
的调用通知条件变量时,线程从睡眠状态中苏醒(解除其阻塞),重新获得互斥元上的锁,并再次检查条件,如果条件已经满足,就从 wait()
返回值,互斥元仍被锁定;如果条件不满足,该线程解锁互斥元,并恢复等待。
这就是为什么需要 std::unique_lock
而不是 std::lock_guard
——等待中的线程在等待期间必须解锁互斥元,并在这之后重新将其锁定,而 std::guard_lock
没有提供这样的灵活性。
在对 wait()
的调用中,条件变量可能会对所提供的条件检查任意多次。然而,它总是在互斥元被锁定的情况下这样做,并且当(且仅当)用来测试条件的函数返回 true,它就会立即返回。
当等待线程重新获取互斥元并检查条件时,如果它并非直接响应另一个线程的通知,这就是所谓的伪唤醒。由于所有的这种伪唤醒的次数和频率根据根据定义是不确定的,所以使用对于条件检查具有副作用的函数是不可取的。如果你这样做,就必须做好多次产生副作用的准备。