[英]What is the difference between std::condition_variable::wait_for and std::condition_variable::wait_until?
区别在于如何表示等待持续时间: 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
等到指定的时间点,但没有说明含义。
time_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秒(+实现工作和调度问题的时间)。
关于旋转与睡眠线程没有区别; 指定wait_for
行为就像使用steady_clock::now() + duration
调用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()
,你可能会在虚假唤醒之前等待几乎整个时间长度,并且下一次等待时间再次开始。 这可能会重复任何次数,使总等待时间无限制 。
IMO,这是一个这样的场景,其中wait_for
无法轻易替换wait_until
,因为它的重置性质。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.