当unique锁被释放并且cv没有被通知时,cv仍然会被唤醒

问题描述 投票:0回答:1

我编写了这段多线程代码片段,试图理解条件变量和互斥锁。

#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()
中。

总结我的问题:

  1. 第一种情况,为什么t1中的cv在没有被通知的情况下就被唤醒了?
  2. 为什么当
    cv.notify_all()
    被注释掉时这不起作用,尽管感觉这行代码似乎是在第一种情况的最后一刻被调用的。
c++ multithreading
1个回答
0
投票

再加一行打印帮助我了解情况

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 **\
© www.soinside.com 2019 - 2024. All rights reserved.