信号在条件变量上而无需锁定锁

signal on condition variable without holding lock

本文关键字:锁定 条件 变量 信号      更新时间:2023-10-16

,所以我发现如果您不在c 11中锁定锁定,请发出条件变量是合法的。这似乎打开了一些令人讨厌的比赛状况的大门:

std::mutex m_mutex;
std::condition_variable m_cv;
T1: 
  std::unique_lock<std::mutex> lock(m_mutex);
  m_cv.wait(lock, []{ return !is_empty(); });
T2:
  generate_data();
  m_cv.notify();

是否可以保证T1永远不会在我们首先检查IS_EMPTY()(返回true)的情况下最终会被T2抢占,从而创建一些数据并在我们可以实际等待之前就标志着条件变量?

如果保证这可以正常工作(我想是这样,否则似乎是故意的API设计),那么这是如何实现Linux和stdlibc++的实际实现?似乎我们需要另一个锁来避免这种情况。

检查谓词和等待在std::condition_variable::wait中未进行原子(解锁锁定和睡眠是原子上执行的)。如果另一个线程在此线程保持静音时可以更改谓词的值,则可能在谓词检查和入睡之间发生通知,并有效地丢失。

在您的示例中,如果T2中的generate_data()可以在不持有m_mutex的情况下更改is_empty()的结果,则可能在T1检查is_empty()和在m_cv上睡觉之间发生通知。在更改对谓词和通知之间的任何时间都保持静音,足以保证在另一个线程中谓词检查和wait调用的原子。看起来像:

{
  std::lock_guard<std::mutex> lk(m_mutex);
  generate_data();
}
m_cv.notify();

甚至

generate_data();
std::lock_guard<std::mutex>(m_mutex); // Lock the mutex and drop it immediately
m_cv.notify();

不能保证 - 如果您不想错过信号,则必须在通知之前锁定静音。一些应用程序可能对缺少信号不可知。

来自MAN PTHREAD_SIGNAL:

pthread_cond_signal()或pthread_cond_broadcast()函数可以由线程调用,无论它是否当前拥有调用pthread_cond_wait()或pthread_cond_timedwait()在等待期间与条件变量相关联的螺纹螺纹的互联面;但是,如果需要可预测的调度行为,则utex将被呼叫pthread_cond_signal()或pthread_cond_broadcast()的线程锁定。