并非所有线程都通知了condition_variable.notify_all()

Not all threads notified of condition_variable.notify_all()

本文关键字:variable notify all condition 知了 线程 通知      更新时间:2023-10-16

我有以下场景:

condition_variable cv;
mutex mut;
// Thread 1:
void run() {
    while (true) {
        mut.lock();
        // create_some_data();
        mut.unlock();
        cv.notify_all();        
    }
}
// Thread 2
void thread2() {
    mutex lockMutex;
    unique_lock<mutex> lock(lockMutex);
    while (running) {
        cv.wait(lock);
        mut.lock();
        // copy data
        mut.unlock();
        // process data
    }
}
// Thread 3, 4... - same as Thread 2

我一直运行线程1以获取新数据。其他线程使用condition_variable等待新数据可用,然后复制它并对其进行一些处理。线程执行的工作在完成所需的时间上是不同的,其思想是线程只有在完成旧数据时才会获得新数据。在此期间获得的数据允许被"遗漏"。我不使用共享互斥锁(仅用于访问数据),因为我不希望线程相互依赖。

上面的代码在Windows上工作得很好,但是现在我在Ubuntu上运行它,我注意到当notify_all()被调用时,只有一个线程被通知,而其他线程只是挂在wait()上。为什么呢?Linux是否需要使用不同的方法来使用condition_variable?

您的代码立即显示UB,因为它重新锁定了cv在退出等待时重新锁定的唯一锁。

还有其他问题,比如没有检测到虚假的唤醒。

最后cv通知所有被通知的当前等待线程。

运气好。

互斥锁和条件变量是同一结构的两个部分。你不能混用互斥锁和cvs。

试试这个:

void thread2() {
    unique_lock<mutex> lock(mut); // use the global mutex
    while (running) {
        cv.wait(lock);
        // mutex is already locked here
        // test condition. wakeups can be spurious
        // copy data
        lock.unlock();
        // process data
        lock.lock();
    }
}

根据本文档:

任何想要等待std::condition_variable的线程都必须

  1. 在同一个互斥锁上获取std::unique_lock,
  2. 执行wait, wait_for或wait_until。等待操作自动释放互斥锁,并挂起对象的执行线程。
  3. 当条件变量被通知,超时过期或发生虚假唤醒时,线程被唤醒,互斥锁被唤醒自动再获得的。然后线程应该检查条件如果唤醒是假的,继续等待。
这段代码

void thread2() {
    mutex lockMutex;
    unique_lock<mutex> lock(lockMutex);
    while (running) {

不能。