繁体   English   中英

为什么在进行条件变量notify之前我们需要一个空的std :: lock_guard?

[英]Why do we need an empty std::lock_guard before doing condition variable notify?

我目前正在研究Google的Filament工作系统。 你可以在这里找到源代码。 令我困惑的部分是这个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();
}

我很困惑为什么我们需要锁定和解锁,即使锁和解锁之间没有动作。 是否有必要进行空锁和解锁?

这有点像黑客。 首先,让我们看看没有它的代码:

mExitRequested.store(true);
mLooperCondition.notify_all();

这里有可能的竞争条件。 其他一些代码可能已经注意到mExitRequested为false并且在我们调用notify_all之后mLooperCondition开始等待notify_all

比赛将是:

  1. 其他线程检查mExitRequested ,这是false
  2. 我们将mExitRequested设置为true
  3. 我们称之为mLooperCondition.notify_all
  4. 其他线程等待mLooperCondition
  5. 哎呀。 等待已经发生的通知。

但是,为了等待条件变量,您必须保持关联的互斥锁。 所以只有当其他一些线程持有mLooperLock互斥锁时才会发生这种情况。 事实上,第4步确实是:“其他线程释放mLooperLock并等待mLooperCondition

因此,为了让这场比赛发生,它必须完全像这样:

  1. 其他线程获得mLooperLock
  2. 其他线程检查mExitRequested ,这是false
  3. 我们将mExitRequested设置为true
  4. 我们称之为mLooperCondition.notify_all
  5. 其他线程等待mLooperCondition ,释放mLooperLock
  6. 哎呀。 等待已经发生的通知。

所以,如果我们将代码更改为:

mExitRequested.store(true);
{ std::lock_guard<Mutex> lock(mLooperLock); }
mLooperCondition.notify_all();

这确保没有其他线程可以检查mExitRequested并查看false然后等待mLooperCondition 因为另一个线程必须在整个过程中保持mLooperLock锁定,这是因为我们在该过程的中间获取了它。

再试一次:

  1. 其他线程获得mLooperLock
  2. 其他线程检查mExitRequested ,这是false
  3. 我们将mExitRequested设置为true
  4. 通过获取和释放nLooperLock ,在另一个线程释放mLooperLock之前,我们不会进行任何前进。
  5. 我们称之为mLooperCondition.notify_all

现在,其他线程阻塞条件或不。 如果没有,那就没问题了。 如果确实如此,那仍然没有问题,因为解锁mLooperLock是条件变量的原子“解锁和等待”操作,保证它看到我们的通知。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM