我需要知道是否有一种方法可以“排队”等待条件变量的线程,以便以正确的顺序唤醒它们......而不需要编写一堆排队代码,即。
在大多数系统中,生产者/消费者模型的以下逆转(在完整邮箱上阻塞)可能无法确保订购:
unique_lock lock1(mutex), lock2(mutex)
ConditionVariable cv
代码块A :(由多个线程调用)
lock(lock1)
timestampOnEntry = now()
cv.wait(lock1) // Don't worry about spurious notifies, out of scope.
somethingRequiringMonotonicOrderOfTimestamps(timestampOnEntry)
unlock(lock1)
代码块B :(由单个线程调用,通常在循环内)
lock(lock2)
somethingVeryVerySlow()
(1) unlock(lock2) // the ordering here is not a mistake
(2) cv.notify_one(lock2) // prevents needless reblocking in code block A
请注意给定顺序中的行(1)和(2)。如果通知线程在代码块B 中的线程解锁后,通知线程将被唤醒,则可以防止代码块A 中不必要的第二个阻塞块。
问题是如果在等待上“阻止”多个线程,我需要知道是否 * notify_one *会按阻止的顺序唤醒它们。可能不是(如在Java中)。如果不是默认情况下,如果有办法指定。
这当然可以通过一堆排队代码完成,但我更喜欢使用预先设定的BOOST方法,无论罐的内容有多复杂。当然,如果我将* cv.notify_one(guard)*转换为* cv.notify_all(guard)*,我将被要求执行排队代码,无论如何。
答案 0 :(得分:3)
标准没有给出这样的保证,notify_one
可以唤醒当前正在等待的任何线程(§30.5.1):
void notify_one() noexcept;
效果:如果有任何线程被阻塞等待*this
,则取消阻止其中一个theads。
确保特定线程对事件做出反应的唯一方法是唤醒所有线程,然后使用一些额外的同步机制将除了正确的线程之外的所有线程发送回休眠状态。
由于平台必须满足的要求,这是一个基本限制:通常条件变量的实现方式是等待线程进入挂起状态,并且在发生通知之前不会再次调度系统。调度程序实现不需要提供用于选择特定线程进行唤醒的功能(实际上很多都没有)。
因此,逻辑的这一部分不可避免地必须由用户代码处理,这反过来意味着你必须唤醒所有线程以使其工作,因为这是确保正确线程被唤醒的唯一方法所有
答案 1 :(得分:2)
你似乎怀疑的简短回答是否定的。
,无法保证notify_one将要唤醒哪个线程(或多个线程)那就是说,我不知道如何制作你的示例代码。具体来说,将互斥量传递给notify_one对我来说没有意义(我不知道任何以这种方式发送信号/广播的平台上的任何条件变量实现)。我不知道你的用例 - 也许你必须有很多线程本地数据阻止安排你的应用程序状态,任何线程都可以获取必要的数据来完成下一个任务?我对此的第一反应是重构代码,而不是关心哪个特定的操作系统线程可以工作,而更多地关注工作本身的排序。