我使用的参考通过以下方式解释了这两者:
wait_for
“阻塞当前线程,直到条件变量被唤醒或在指定的超时持续时间之后”wait_until
“阻塞当前线程,直到条件变量被唤醒或到达指定的时间点”
有什么不同?将wait_until
自旋,以便线程在收到信号时可以准确地(或多或少地)继续,而wait_for
只是在那时将线程重新添加到调度中?
我使用的参考通过以下方式解释了这两者:
wait_for
“阻塞当前线程,直到条件变量被唤醒或在指定的超时持续时间之后”
wait_until
“阻塞当前线程,直到条件变量被唤醒或到达指定的时间点”
有什么不同?将wait_until
自旋,以便线程在收到信号时可以准确地(或多或少地)继续,而wait_for
只是在那时将线程重新添加到调度中?
不同之处在于等待持续时间的表示方式:wait_for
需要一个相对时间(“等待最多 10 秒”),而wait_until
需要一个绝对时间(“等到 2012 年 10 月 30 日 12:00”)。
比较时间参数的声明:
// wait_for:
const std::chrono::duration<Rep, Period>& rel_time
// wait_until:
const std::chrono::time_point<Clock, Duration>& abs_time
您的问题和其他答案都重复了差异;wait_for
等待指定的时间并一直wait_until
等到指定的时间点,但没有说明其含义。
Atime_point
有一个关联的时钟,该时钟用于确定是否到了适当的时间。这意味着该功能会考虑时钟调整wait_until
。wait_until(..., system_clock::now() + std::chrono::seconds(10))
如果时钟恰好在等待结束前一小时调回,则可能会等待一个小时零 10 秒。
持续时间没有任何关联的时钟,因此wait_for
选择自己的时钟。该标准规定它使用std::steady_clock,它不能被调整并且以相对于实时的稳定速率前进。这意味着wait_for
无论对任何时钟进行任何调整,都会等待指定的时间。wait_for(..., std::chrono::seconds(10))
保证等待 10 秒(+ 一些时间让实现工作和调度问题)。
旋转与休眠线程没有区别;aswait_for
被指定为表现得好像它调用wait_until
了steady_clock::now() + duration
.
这是标准中详细说明的部分:
2实现在从超时返回时必然会有一些延迟。中断响应、函数返回和调度中的任何开销都会导致“实现质量”延迟,表示为持续时间D i。理想情况下,此延迟为零。此外,任何对处理器和内存资源的争用都会导致“管理质量”延迟,表示为持续时间D m。延迟持续时间可能因超时而异,但在所有情况下,越短越好。
3名称以结尾的成员函数
_for
采用指定持续时间的参数。这些函数产生相对超时。实现应该使用稳定的时钟来测量这些功能的时间。给定一个持续时间参数D t,超时的实时持续时间是D t + D i + D m。4名称以结尾的成员函数
_until
采用指定时间点的参数。这些函数产生绝对超时。实现应使用时间点中指定的时钟来测量这些功能的时间。给定一个时钟时间点参数C t ,当在超时期间没有调整时钟时,从超时返回的时钟时间点应该是 C t + D i + D m 。如果在超时期间将时钟调整到时间C a,则行为应如下所示:
— 如果C a > C t,等待函数应该尽快唤醒,即C a + D i + D m,因为超时已经满足。[注意:当针对稳定时钟测量时,此规范可能会导致等待的总持续时间减少。—尾注 ]
— 如果C a <= C t,等待函数不应该超时,直到Clock::now()
返回时间C n >= C t,即在C t + D i + D m唤醒. [ 注意:当时钟向后调整时,此规范可能会导致在针对稳定时钟测量时等待的总持续时间增加。当时钟向前调整时,此规范可能会导致在针对稳定时钟测量时等待的总持续时间减少。—结束注释]
实现应在上述指定时间的任何时间点从此类超时返回到它将从C t与调用_until
函数的时间点之间的差值的稳定时钟相对超时返回的时间。[注意:当时钟向前调整时,实现应该减少等待的持续时间。——尾注]
wait_for
将等待一定的时间。例如,它将等待两秒钟。wait_until
将等到某个时间到达。例如,它将等到时钟到达 2013 年 7 月 23 日晚上 11:22:34。正如 Anthony Williams 的书中所解释的,这是它们用法上的一个重要区别:
考虑以下示例,其中条件变量等待超时:
std::condition_variable cv;
bool done;
std::mutex m;
bool wait_loop()
{
auto const timeout= std::chrono::steady_clock::now()+
std::chrono::milliseconds(500);
std::unique_lock<std::mutex> lk(m);
while(!done)
{
if(cv.wait_until(lk,timeout)==std::cv_status::timeout)
break;
}
return done;
}
如果您没有将谓词传递给等待,这是等待具有时间限制的条件变量的推荐方法。这样,循环的总长度是有界的。正如您在 4.1.1 节中看到的,如果您不传入谓词,则在使用条件变量时需要循环,以处理虚假唤醒。如果您
wait_for()
在循环中使用,您可能会在虚假唤醒之前等待几乎全部时间,并且下一次等待时间再次开始。这可以重复任意次数,使总等待时间无界。
wait_for
IMO,这是一种无法轻易更换的场景wait_until
,因为它具有重置性质。