我们以
C++11
的 API 接口定义来描述
大家在编写多线程类的程序时,会用到信号量 condition_variable,有没有疑惑过为什么 cv 这类接口,在调用 wait/notify
时候还需要用一个 mutex
。
为什么 cv.wait()
需要用 mutex
保护?
常见的 cv
代码实现类似下方,包含三个部分:检查条件是否满足;如果不满足等待到满足;等待到满足后执行逻辑。
std::unique_lock<std::mutex> lock(cv_m);
while (!cond_ok()) { // 1. 检查条件是否满足
wait(lock); // 2. 等待信号
}
// do somethings with cond // 3. 执行逻辑
如果没有一个锁保护这三个部分,会出现两种情况:
- 在第一部分检查条件不满足,准备进行第二部分
wait
信号时,另一个线程达到了信号条件并signal
,然后执行到wait
。这个时候wiat
就永远挂在这儿了。 - 在第二部分执行完成后,认为已经达到条件,准备执行第三部分的业务逻辑。另一个线程修改了条件。第三部分执行的假设是条件已经满足,违反了假设,业务逻辑可能会有问题。
所以一般会通过一个 mutex 将上述三个部分看起一个原子操作,将检查条件是否完成与等待信号量同时执行。其它线程如果 signal 信号,一定是在检查条件之前或者wait之后。