【发布时间】:2021-02-25 06:56:48
【问题描述】:
我在尝试从线程通知 condition_variable 时遇到死锁。
这是我的 MCVE:
#include <iostream>
#include <boost/thread.hpp>
#include <boost/thread/mutex.hpp>
#include <boost/thread/condition_variable.hpp>
static boost::mutex m_mutex;
static boost::condition_variable m_cond;
void threadFunc()
{
std::cout << "LOCKING MUTEX" << std::endl;
boost::mutex::scoped_lock lock( m_mutex );
std::cout << "LOCKED, NOTIFYING CONDITION" << std::endl;
m_cond.notify_all();
std::cout << "NOTIFIED" << std::endl;
}
int main( int argc, char* argv[] )
{
while( true )
{
std::cout << "TESTING!!!" << std::endl;
boost::mutex::scoped_lock lock( m_mutex );
boost::thread thrd( &threadFunc );
//m_cond.wait( lock );
while ( !m_cond.timed_wait(lock,boost::posix_time::milliseconds(1)) )
{
std::cout << "WAITING..." << std::endl;
}
static int pos = 0;
std::cout << "DONE!!! " << pos++ << std::endl;
thrd.join();
}
return 0;
}
如果使用m_cond.wait( lock );,我看到每次尝试都会写入DONE!!!,这里没问题。
如果我使用while ( !m_cond.timed_wait(lock,boost::posix_time::milliseconds(1)) ) 循环,我会看到DONE!!! 被写入了几次尝试,并且在某些时候,我得到了一个死锁,等待终于永远不会结束:
TESTING!!!
LOCKING MUTEX
LOCKED, NOTIFYING CONDITION
NOTIFIED
WAITING...
WAITING...
WAITING...
WAITING...
WAITING...
WAITING...
...
我已经阅读了有关 stackoverflow 的其他帖子(例如 Condition variable deadlock):他们提到如果在条件的等待函数运行之前调用 notify_all 可能会发生这种情况,因此必须使用互斥锁来防止这种情况发生。但我觉得这就是我正在做的事情:
- 我在创建线程之前锁定了互斥锁
- 然后线程无法在到达
m_cond.timed_wait之前通知(然后互斥锁被解锁) - 在循环内,如果超时,
timed_wait会重新锁定互斥锁,因此无法完成通知,我们会打印“WITTING...”并在再次准备好接收通知时释放互斥锁
那么为什么会发生死锁呢?是否可以在timed_wait 检测到超时和重新锁定互斥锁之间通知条件?
【问题讨论】:
-
我已经用 c++ 标准库试过了,它没有死锁:compiler-explorer.com/z/Gh7da7
-
@JVApen:点击了您的链接。在尝试 #54! 后进入无限循环,重试两次,没关系,第一次尝试,在尝试 #284 后它开始等待永远......所以这显然不是一个提升问题。
-
你似乎没有防备spurious wakeups。
-
...另外,在持有锁时通知可能是一种悲观。
-
@TedLyngmo Rainer 解释了为什么在此处通知锁时需要保持互斥锁:modernescpp.com/index.php/… - 尽管在这种情况下它只会导致额外的毫秒等待而不是永远等待。跨度>
标签: c++ multithreading boost-thread condition-variable