如果条件变量向锁定的线程发出信号怎么办?

What if a condition variable signals to a locked thread?

在下面的(伪)代码中,cond 可能会在不应该唤醒的时候唤醒,无论出于何种原因。所以我在那里放了一个 while 循环。当它醒来时,它仍然会消耗锁,所以可以保证 out() 只有一个线程在做它的工作。

但是,如果在 out() 中出现虚假唤醒,同时 in()out() 发出信号,但是就在那一刻 out() 由于虚假唤醒已被锁定。那么如果 cond 向锁定的线程发出信号会发生什么?

in()
    inLock.lock()
    isEmpty = false
    cond.signal()
    inLock.unlock()

out()
    outLock.lock()
    while isEmpty
        cond.wait(outLock)
    isEmpty = true
    outLock.unlock()


注意

嗯,为了 100% 安全,我知道我可以对 in()out() 使用一个互斥体,但是我使用的数据结构在输入和输入时是 100% 安全的输出同时发生;它是一种队列。我认为在填充一些新数据时阻止从队列中读取任何内容是一种性能妥协,反之亦然。

我确实考虑过使用信号量,但问题是很多 C 和 C++ 库出于某种原因没有实现信号量。

So what happens if the cond signals to a locked thread?

信号永远丢失了。如果在调用 pthread_cond_signal 时没有线程在等待信号,那么 pthread_cond_signal 什么都不做。

in() 线程设置 isEmpty = falseout() 线程测试 while (isEmpty) 时,您必须使用相同的互斥体。否则,可能会发生这种情况:

  1. out()线程测试isEmpty,发现是真的;
  2. in() 线程将 isEmpty 设置为 false 并向条件变量发出信号(但没有人醒来,因为还没有人在等待);
  3. out() 线程调用 cond.wait() 并永远阻塞,尽管队列不再为空。

请注意,在此序列中没有虚假唤醒 - 这只是一个普通的旧竞争条件。

只要您使用与测试 isEmpty 时相同的互斥锁来更新 isEmpty,就不会发生这种交错。

由于isEmpty正在被两个不同的线程读取和修改,因此在不受保护的情况下访问它是错误的。当您允许 inout 使用不同的锁实例时,这实际上就是您正在做的事情。

在同一个条件变量上使用不同的锁实例违反了POSIX API for pthread_cond_wait()(强调我的)。

The effect of using more than one mutex for concurrent pthread_cond_wait() or pthread_cond_timedwait() operations on the same condition variable is undefined; that is, a condition variable becomes bound to a unique mutex when a thread waits on the condition variable, and this (dynamic) binding ends when the wait returns.