gpt4 book ai didi

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

转载 作者:可可西里 更新时间:2023-11-01 17:43:58 26 4
gpt4 key购买 nike

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

我很困惑为什么我们需要锁定和解锁,即使在锁定和解锁之间没有任何 Action 。是否存在需要这种空锁和解锁的情况?

最佳答案

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

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

这里可能存在竞争条件。其他一些代码可能已经注意到 mExitRequested 为假,并在我们调用 notify_all 后立即开始等待 mLooperCondition

比赛将是:

  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 的解锁是条件变量的原子“解锁并等待”操作,保证它看到我们的通知。

关于c++ - 为什么我们在进行条件变量通知之前需要一个空的 std::lock_guard?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56520681/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com