所以我刚刚发现,如果你没有在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抢占,它会创建一些数据,并在我们可以真正等待它之前用信号通知条件变量?
如果这保证可以工作(我想是这样的,否则它看起来就像是故意设计的糟糕的应用程序接口),那么这实际上是如何在linux和stdlibc++上实现的呢?看起来我们需要另一个锁来避免这种情况。
发布于 2014-01-30 02:32:41
在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();发布于 2014-01-30 02:28:12
这是不能保证的-如果你不想错过信号,那么你必须在通知之前锁定互斥量。一些应用程序可能对丢失信号是不可知的。
来自man pthread_signal:
pthread_cond_signal()或pthread_cond_broadcast()函数可以由线程调用,无论它当前是否拥有调用pthread_cond_wait()或pthread_cond_timedwait()的线程在等待期间与条件变量相关联的互斥锁;但是,如果需要可预测的调度行为,则调用pthread_cond_signal()或pthread_cond_broadcast()的线程将锁定该互斥锁。
https://stackoverflow.com/questions/21439359
复制相似问题