我编写了这段多线程代码片段,试图理解条件变量和互斥锁。
#include<iostream>
#include <thread>
#include <condition_variable>
#include <chrono>
using namespace std;
int main() {
mutex mtx;
condition_variable cv;
int counter = 0;
// after releasing lock, what happens
auto fn = [&] (int i) {
{
unique_lock<mutex> lock(mtx);
cv.wait(lock, [&] {return counter % 2 == i;});
std::cout << i << " exited wait " << std::endl;
counter++;
}
std::cout << i << " Sleeping" << std::endl;
this_thread::sleep_for(chrono::seconds(1));
std::cout << "Printing " << i << std::endl;
cv.notify_all();
};
thread t0(fn, 0);
thread t1(fn, 1);
t0.join();
t1.join();
return 0;
}
我期待
cv.wait
语句要等到它得到 cv.notify_all()
为止。然而,这个程序的输出是
0 exited wait
0 Sleeping
1 exited wait
1 Sleeping
Printing 0
Printing 1
这表明线程 t1 的 cv 甚至在 t0 调用
notify_all()
之前就已唤醒。
起初,我认为这是因为 t0 释放了 mtx 上的锁,从而隐式唤醒了被相同互斥锁阻塞的 cvs。更让我困惑的是,当我注释掉cv.notify_all();
时,这就是输出
0 exited wait
0 Sleeping
Printing 0
** Process Stopped **
这表示线程 t1 卡在
cv.wait()
中。
总结我的问题:
cv.notify_all()
被注释掉时这不起作用,尽管感觉这行代码似乎是在第一种情况的最后一刻被调用的。再加一行打印帮助我了解情况
0 entering wait
0 exited wait
0 Sleeping
1 entering wait
1 exited wait
1 Sleeping
Printing 0
Printing 1
** Process exited - Return Code: 0 **
看起来 t1 被互斥锁阻塞了,因为 t0 先抢到了锁。当 t0 释放锁时,t1 会跳过条件变量,因为谓词返回 true。
在t1先抢到锁的情况下,它确实进入了条件变量wait,需要notify_all()才能唤醒。
1 entering wait
0 entering wait
0 exited wait
0 Sleeping
Printing 0
1 exited wait
1 Sleeping
Printing 1
** Process exited - Return Code: 0 **\