gpt4 book ai didi

c++ - condition_variable.notify_all 是否应该被互斥锁覆盖?

转载 作者:太空狗 更新时间:2023-10-29 20:34:22 30 4
gpt4 key购买 nike

我已经实现了一个类,它允许我将线程与条件变量同步。关于 notify_all 应该在锁内还是在锁外完成,我发现了相互矛盾的信息。我找到了以两种方式构造的示例。

优先释放锁的说法是为了防止等待线程在被通知释放后立即阻塞在互斥体上。

反对首先释放锁的论点是等待线程可能会错过通知。

发布函数的两个版本在这里:

// version 1 - unlock then notify.
void release(int address = 1)
{
{
std::lock_guard<std::mutex> lk(_address_mutex);
_address = address;
}
_cv.notify_all();
}

// version 2 - notify then unlock
void release(int address = 1)
{
std::lock_guard<std::mutex> lk(_address_mutex);
_address = address;
_cv.notify_all();
}

供引用,等待代码如下所示:

bool wait(const std::chrono::microseconds dur, int address = 1)
{
std::unique_lock<std::mutex> lk(_address_mutex);
if (_cv.wait_for(lk, dur, [&] {return _address == address; }))
{
_address = 0;
return true;
}
return false;
}

在版本 1 中是否存在等待线程丢失通知的风险,其中允许互斥量在 notify_all 之前超出范围?如果是这样,它是如何发生的? (我不清楚这是如何导致错过通知的。)

我可以清楚地看到在通知期间保持互斥量锁定是如何导致等待线程立即进入等待状态的。但如果可以防止错过通知,这是一个很小的代价。

最佳答案

如果在条件测试状态更改和通知之间的某个时间间隔内持有互斥锁,则没有释放锁的风险。

{
std::lock_guard<std::mutex> lk(_address_mutex);
_address = address;
}
_cv.notify_all();

这里,互斥体在 _address 改变后被解锁。所以没有风险。

如果我们将 _address 修改为原子的,天真地这看起来是正确的:

{
std::lock_guard<std::mutex> lk(_address_mutex);
}
_address = address;
_cv.notify_all();

但事实并非如此;在这里,互斥量在修改条件测试和通知之间的整个期间被释放,

_address = address;
{
std::lock_guard<std::mutex> lk(_address_mutex);
}
_cv.notify_all();

然而,上面的内容再次变得正确(如果有点奇怪的话)。


风险在于条件测试将在互斥量处于事件状态(为假)的情况下进行评估,然后更改,然后发送通知,然后等待线程等待通知并释放互斥量。

waiting|signalling
lock
test
test changed
notification
listen+unlock

以上是错过通知的示例。

只要我们在测试更改之后和通知之前的任何地方持有互斥锁,它就不会发生。

关于c++ - condition_variable.notify_all 是否应该被互斥锁覆盖?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48958530/

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