我需要在调用condition_variable :: notify()之前锁定互斥量吗?

5

我正在阅读一些 condition_variable 的示例代码:

在 cppreference 上,notify_one() 被这样调用: https://en.cppreference.com/w/cpp/thread/condition_variable

{
    std::lock_guard lk(m);
    ready = true;
    std::cout << "main() signals data ready for processing\n";
}
cv.notify_one();

从上面的代码可以清楚地看出,调用notify_one()不需要使用任何mutex。但在cplusplus.com上,代码像这样:https://cplusplus.com/reference/condition_variable/condition_variable/
std::unique_lock<std::mutex> lck(mtx);
ready = true;
cv.notify_all();

似乎在调用notify_all()之前需要使用mutex。
我有点困惑,调用notify_*()函数是否需要mutex?

互斥锁被锁定以同步两个示例中的 ready = true - 463035818_is_not_a_number
3
cppreference明确指出“通知时不需要持有锁定”。您只需要在修改共享变量时使用锁定,即使共享变量是原子的,也需要使用锁定。 - François Andrieux
2
一则旁注:在我看来,cppreference.com比cplusplus.com更好。 - wohlstad
如果我没记错的话,只有在“等待”时才需要“锁”。 - Refugnic Eternium
欢迎来到StackOverflow。如果答案解决了您的问题,您可以点击“✔”将其标记为采纳答案。有足够的声望后,您也可以给任何有帮助的答案点赞(详见此处:https://stackoverflow.com/help/someone-answers)。 - wohlstad
1个回答

2

在持有互斥锁的情况下,调用notify_onenotify_all不强制的

std::condition_variable 文档中提到:
修改共享变量的线程需要执行以下三件事之一:

在 std::condition_variable 上执行 notify_one 或 notify_all(无需持有锁即可通知

(强调是我的)

然而,在持有锁的情况下调用notify_*可能会带来一些性能优势

根据这里的回答评论(由@DavidSchwartz提供),解释如下:

在调用notify_all之前解锁互斥锁是没有必要的。如果在持有互斥锁的情况下调用notify_all,则大多数现代实现都知道它不能使任何线程准备运行(因为它们需要获取互斥锁才能向前推进),并且可以进行等待变形优化。在这种编码方式中,notify_all和lck的析构函数都可以使线程准备运行,从而降低性能。


1
非常有趣的输入,谢谢。我一直以为相反的情况,因为文档仍然指出:“通知线程不需要持有与等待线程相同的互斥锁;事实上这样做是一种劣化,因为被通知的线程会立即再次阻塞,等待通知线程释放锁。”听起来像是聪明的现代编译器需要改变我的编码 :) - Cedric
@Cedric 我也感到很惊讶。在我上面提到的另一个答案中,我最初是在锁定之外调用了notify_方法。无论如何,如果这个答案对您有用,请随意点赞;-) - wohlstad
@Cedric 在 https://en.cppreference.com/w/cpp/thread/condition_variable/notify_one 中也提到了 pthreads 方法。 - Cubbi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接