[英]Do I have to lock to check a work-available flag used with a condition variable before setting it, and if so why?
I have a worker thread in a thread pool that behaves like so:我在线程池中有一个工作线程,其行为如下:
while (running)
{
std::unique_lock<std::mutex> lock(m_mutex);
m_condition.wait(lock, [&] { return m_workAvailable; });
m_workAvailable = false;
lock.unlock();
// (Perform work...)
}
When I drop work into this worker thread, it looks like so:当我将工作放到这个工作线程中时,它看起来像这样:
// (enqueue the actual work item...)
if (!m_workAvailable)
{
std::lock_guard<std::mutex> lock(m_mutex);
m_workAvailable = true;
}
m_condition.notify_one();
After seeing the behavior of this code in practice I'm guessing that there is some kind of concurrency bug related to the在实践中看到此代码的行为后,我猜测存在某种与
if(! m_workAvailable)
check here, which is meant to bypass contention for the mutex unless necessary.在这里检查,这意味着除非必要,否则会绕过互斥锁的争用。 But if this is so, I don't actually see the scenario that would cause this problem.但如果是这样,我实际上并没有看到会导致这个问题的场景。
[ Update : I have tried this with m_workAvailable
being both bool
and volatile bool
. [更新:我已经尝试过m_workAvailable
既是bool
又是volatile bool
。 I have not as yet tried std::atomic<bool>
, though as far as I understand that wouldn't be fundamentally different from volatile bool
here.我还没有尝试过std::atomic<bool>
,但据我所知,这与这里的volatile bool
并没有根本的不同。 ] ]
Questions:问题:
Is this indeed a concurrency bug?这确实是一个并发错误吗?
Yes.是的。
If so, why -- what does this allow to go wrong?如果是这样,为什么 - 这允许 go 出错?
It's undefined behavior.这是未定义的行为。 The standards don't say what happens if a non-atomic type is accessed by one thread while another thread is, or might be, modifying it.标准没有说明如果一个线程访问非原子类型而另一个线程正在或可能正在修改它会发生什么。 Your code does that.你的代码就是这样做的。 So it can break in any imaginable way.所以它可以以任何可以想象的方式破裂。
If so, is there any way of doing what I'm doing here that doesn't require me to lock the mutex every single time a piece of work comes in?如果是这样,有什么方法可以做我在这里做的事情,而不需要我在每次工作进入时都锁定互斥锁?
Yes, Do this:是的,这样做:
{
std::lock_guard<std::mutex> lock(m_mutex);
m_workAvailable = true;
m_condition.notify_one();
}
Your platform, if it has a good implementation, will detect that the mutex is already held when you call notify_one
and avoid synchronizing again.您的平台,如果它具有良好的实现,将在您调用notify_one
时检测到互斥锁已被持有并避免再次同步。 The net effect will be roughly the same as not acquiring the mutex during the set of m_workAvailable
if the mutex isn't contended.如果互斥锁没有被争用,净效果将与在m_workAvailable
集合期间不获取互斥锁大致相同。 (If it is contended, the cost is unavoidable anyway.) (如果有争议,无论如何成本是不可避免的。)
I have not as yet tried
std::atomic<bool>
, though as far as I understand that wouldn't be fundamentally different fromvolatile bool
here.我还没有尝试过std::atomic<bool>
,但据我所知,这与这里的volatile bool
并没有根本的不同。
Umm, huh?嗯,嗯? What threading standard defines the behavior when a volatile bool
is accessed in one thread while another thread is, or might be, modifying it?什么线程标准定义了在一个线程中访问volatile bool
而另一个线程正在或可能正在修改它时的行为? I don't know of any except Microsoft Visual Studio.我不知道除了 Microsoft Visual Studio 之外的任何东西。 By contrast, std::atomic<bool>
has well-defined semantics in that case.相比之下, std::atomic<bool>
在这种情况下具有明确定义的语义。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.