1

我需要知道是否有一种方法可以“排队”等待条件变量的线程,以便它们以正确的顺序被唤醒……也就是说,无需编写一堆排队代码。

在大多数系统中,生产者/消费者模型的以下反转(在满邮箱上阻塞)可能无法确保排序:

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)*,无论如何我都需要执行排队代码。

4

2 回答 2

3

标准没有给出这样的保证,notify_one可以唤醒当前正在等待的任何线程(§30.5.1):

void notify_one() noexcept; 效果:如果任何线程被阻塞等待*this,解除阻塞其中一个线程。

确保特定线程对事件作出反应的唯一方法是唤醒所有线程,然后使用一些额外的同步机制将除正确线程之外的所有线程发送回睡眠状态。

由于平台必须满足的要求,这是一个基本限制:通常条件变量的实现方式是等待线程进入挂起状态,并且在发生通知之前不会再次被系统调度。调度程序实现不需要提供选择特定线程以唤醒的功能(实际上很多都没有)。

所以这部分逻辑不可避免地必须由用户代码处理,这反过来意味着你必须唤醒所有线程以使其工作,因为这是确保正确线程被唤醒的唯一方法。

于 2013-11-07T09:36:11.117 回答
2

正如您似乎怀疑的那样,简短的回答是否定的。不一定保证哪个线程(或多个线程) notify_one 将被唤醒。

也就是说,我不确定如何处理您的示例代码。具体来说,将互斥锁传递给 notify_one 对我来说没有意义(我不知道在任何平台上以这种方式发出信号/广播的任何条件变量实现)。我不知道你的用例——也许你必须有很多线程本地数据来阻止你安排你的应用程序状态,这样任何线程都可以获取必要的数据来完成下一个任务?我对此的第一反应是重构代码以较少关心哪个特定的操作系统线程执行哪些工作,而更多地关注工作本身的顺序。

于 2013-11-07T09:30:20.297 回答