在通知之前进行手动解锁

8
感谢Scott Meyers博士的书籍,第263页,我最近发现了condition_variable,所以我不得不搜索关于它的内容以更好地研究它。

https://en.cppreference.com/w/cpp/thread/condition_variable

我有几个与之相关的问题,因为我已经思考了好几天,但仍然不理解。

我的问题是关于这段代码的:

// Manual unlocking is done before notifying, to avoid waking up
// the waiting thread only to block again (see notify_one for details)
lk.unlock();
cv.notify_one();

1)我不明白cppreference的作者在评论中所说的“等待线程,只会再次阻塞”是什么意思,因为我甚至不知道如何翻译它。

2)它确切表示哪些线程,以及为什么特别表示它们。

3)它表示thread_worker还是主线程(父线程)?

4)他们选择这样做的原因是什么?

如果作者先发出通知,然后手动解锁,这会有什么变化?

1个回答

6
这是一项次要的并且通常不相关的优化。这种担忧是因为每个在调用notifynotify_all后唤醒的线程都必须在允许其继续之前锁定互斥量。如果调用unlock发生在调用notify_one(或notify)之后,唤醒的线程将不得不等待直到调用线程解锁它。如果在通知调用之前进行解锁,则一个被唤醒的线程可以立即获取互斥量。

我发布了一条新评论,也完成了我的第一篇帖子。 - Dev
谢谢Pete Becker。您能否准确地解释一下,当cppreference的作者写道:在通知之前进行手动解锁,以避免唤醒等待线程只是为了再次阻塞(有关详细信息,请参见notify_one)在示例中https://en.cppreference.com/w/cpp/thread/condition_variable什么意思“等待线程只是为了再次阻塞”因为我试图用法语理解它。在cppreference的示例中,它指的是哪个线程?是主线程还是thread_worker?感谢您的帮助。 - Dev
2
主线程在条件变量上阻塞,等待工作线程完成。当工作线程完成时,它调用 notify_one 来唤醒主线程。问题是如果互斥锁不可用,主线程可能会受到影响。 - Pete Becker
最后,我认为我理解了,请纠正我,亲爱的Pete,如果我不正确:1)互斥锁不能在同时被两个线程共享;2)在句子“等待线程只会再次阻塞”中,“等待线程”指的是主线程;3)因此,如果通知在“解锁”之前,则在主线程尚未再次获取std::mutex之前会有第一次虚假唤醒。但是,在解锁之后,会有第二次唤醒,这是好的,因为主线程此时已经获取了互斥锁并恢复执行。你觉得呢? - Dev
2
虚假唤醒是完全不同的事情。条件变量允许在没有调用notify..l的情况下释放线程。这就是虚假唤醒,这就是为什么代码通常运行循环的原因:while (!condition) condition_variable.wait(); - Pete Becker
2
当线程被条件变量释放时,有两个步骤:唤醒线程和锁定互斥锁。如果互斥锁由于任何原因而被锁定,则线程将阻塞,直到持有锁的线程释放该锁。 - Pete Becker

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