[英]Why do we need an empty std::lock_guard before doing condition variable notify?
I am currently studying Google's Filament job system. 我目前正在研究Google的Filament工作系统。 You can find the source code here .
你可以在这里找到源代码。 The part that confuses me is this requestExit() method:
令我困惑的部分是这个requestExit()方法:
void JobSystem::requestExit() noexcept {
mExitRequested.store(true);
{ std::lock_guard<Mutex> lock(mLooperLock); }
mLooperCondition.notify_all();
{ std::lock_guard<Mutex> lock(mWaiterLock); }
mWaiterCondition.notify_all();
}
I am confused why we need to lock and unlock even though there is no action in between the lock and unlock. 我很困惑为什么我们需要锁定和解锁,即使锁和解锁之间没有动作。 Are there any cases where this empty lock and unlock is necessary?
是否有必要进行空锁和解锁?
This is a bit of a hack. 这有点像黑客。 First, let's look at the code without that:
首先,让我们看看没有它的代码:
mExitRequested.store(true);
mLooperCondition.notify_all();
There's a possible race condition here. 这里有可能的竞争条件。 Some other code might have noticed that
mExitRequested
was false and started waiting for mLooperCondition
right after we called notify_all
. 其他一些代码可能已经注意到
mExitRequested
为false并且在我们调用notify_all
之后mLooperCondition
开始等待notify_all
。
The race would be: 比赛将是:
mExitRequested
, it's false
. mExitRequested
,这是false
。 mExitRequested
to true
. mExitRequested
设置为true
。 mLooperCondition.notify_all
. mLooperCondition.notify_all
。 mLooperCondition
. mLooperCondition
。 But in order to wait for a condition variable, you must hold the associated mutex. 但是,为了等待条件变量,您必须保持关联的互斥锁。 So that can only happen if some other thread held the
mLooperLock
mutex. 所以只有当其他一些线程持有
mLooperLock
互斥锁时才会发生这种情况。 In fact, step 4 would really be: "Other thread releases mLooperLock
and waits for mLooperCondition
. 事实上,第4步确实是:“其他线程释放
mLooperLock
并等待mLooperCondition
。
So, for this race to happen, it must happen precisely like this: 因此,为了让这场比赛发生,它必须完全像这样:
mLooperLock
. mLooperLock
。 mExitRequested
, it's false
. mExitRequested
,这是false
。 mExitRequested
to true
. mExitRequested
设置为true
。 mLooperCondition.notify_all
. mLooperCondition.notify_all
。 mLooperCondition
, releasing mLooperLock
. mLooperCondition
,释放mLooperLock
。 So, if we change the code to: 所以,如果我们将代码更改为:
mExitRequested.store(true);
{ std::lock_guard<Mutex> lock(mLooperLock); }
mLooperCondition.notify_all();
That ensures that no other thread could check mExitRequested
and see false
and then wait for mLooperCondition
. 这确保没有其他线程可以检查
mExitRequested
并查看false
然后等待mLooperCondition
。 Because the other thread would have to hold the mLooperLock
lock through the whole process, which can't happen since we acquired it in the middle of that process. 因为另一个线程必须在整个过程中保持
mLooperLock
锁定,这是因为我们在该过程的中间获取了它。
Trying it again: 再试一次:
mLooperLock
. mLooperLock
。 mExitRequested
, it's false
. mExitRequested
,这是false
。 mExitRequested
to true
. mExitRequested
设置为true
。 nLooperLock
, we do not make any forward progress until the other thread releases mLooperLock
. nLooperLock
,在另一个线程释放mLooperLock
之前,我们不会进行任何前进。 mLooperCondition.notify_all
. mLooperCondition.notify_all
。 Now, either the other thread blocks on the condition or it doesn't. 现在,其他线程阻塞条件或不。 If it doesn't, there's no problem.
如果没有,那就没问题了。 If it does, there's still no problem because the unlocking of
mLooperLock
is the condition variable's atomic "unlock and wait" operation, guaranteeing that it sees our notify. 如果确实如此,那仍然没有问题,因为解锁
mLooperLock
是条件变量的原子“解锁和等待”操作,保证它看到我们的通知。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.