并非所有线程都收到 condition_variable.notify_all() 的通知

Not all threads notified of condition_variable.notify_all()

我有以下情况:

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 直到有新数据可用,然后复制它并对其进行一些处理。线程执行的工作在完成所需的时间上有所不同,其思想是线程只有在完成旧数据时才会获取新数据。同时得到的数据允许为"missed"。我不使用共享互斥量(仅用于访问数据),因为我不希望线程相互依赖。

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

靠运气。

互斥锁和条件变量是同一构造的两个部分。您不能混合和匹配互斥体和 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();
    }
}

根据 this documentation:

Any thread that intends to wait on std::condition_variable has to

  1. acquire a std::unique_lock, on the same mutex as used to protect the shared variable
  2. execute wait, wait_for, or wait_until. The wait operations atomically release the mutex and suspend the execution of the thread.
  3. When the condition variable is notified, a timeout expires, or a spurious wakeup occurs, the thread is awakened, and the mutex is atomically reacquired. The thread should then check the condition and resume waiting if the wake up was spurious.

这个代码

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

不会那样做。

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

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

最后,cv 通知所有 onky 通知的当前等待线程。如果稍后出现一个线程,则没有骰子。