![](/img/trans.png)
[英]Do I have to acquire lock before calling condition_variable.notify_one()?
[英]Do I have to lock to check a work-available flag used with a condition variable before setting it, and if so why?
我在线程池中有一个工作线程,其行为如下:
while (running)
{
std::unique_lock<std::mutex> lock(m_mutex);
m_condition.wait(lock, [&] { return m_workAvailable; });
m_workAvailable = false;
lock.unlock();
// (Perform work...)
}
当我将工作放到这个工作线程中时,它看起来像这样:
// (enqueue the actual work item...)
if (!m_workAvailable)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_workAvailable = true;
}
m_condition.notify_one();
在实践中看到此代码的行为后,我猜测存在某种与
if(! m_workAvailable)
在这里检查,这意味着除非必要,否则会绕过互斥锁的争用。 但如果是这样,我实际上并没有看到会导致这个问题的场景。
[更新:我已经尝试过m_workAvailable
既是bool
又是volatile bool
。 我还没有尝试过std::atomic<bool>
,但据我所知,这与这里的volatile bool
并没有根本的不同。 ]
问题:
这确实是一个并发错误吗?
是的。
如果是这样,为什么 - 这允许 go 出错?
这是未定义的行为。 标准没有说明如果一个线程访问非原子类型而另一个线程正在或可能正在修改它会发生什么。 你的代码就是这样做的。 所以它可以以任何可以想象的方式破裂。
如果是这样,有什么方法可以做我在这里做的事情,而不需要我在每次工作进入时都锁定互斥锁?
是的,这样做:
{
std::lock_guard<std::mutex> lock(m_mutex);
m_workAvailable = true;
m_condition.notify_one();
}
您的平台,如果它具有良好的实现,将在您调用notify_one
时检测到互斥锁已被持有并避免再次同步。 如果互斥锁没有被争用,净效果将与在m_workAvailable
集合期间不获取互斥锁大致相同。 (如果有争议,无论如何成本是不可避免的。)
我还没有尝试过
std::atomic<bool>
,但据我所知,这与这里的volatile bool
并没有根本的不同。
嗯,嗯? 什么线程标准定义了在一个线程中访问volatile bool
而另一个线程正在或可能正在修改它时的行为? 我不知道除了 Microsoft Visual Studio 之外的任何东西。 相比之下, std::atomic<bool>
在这种情况下具有明确定义的语义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.