33

我使用的参考通过以下方式解释了这两者:

  • wait_for“阻塞当前线程,直到条件变量被唤醒或在指定的超时持续时间之后”

  • wait_until“阻塞当前线程,直到条件变量被唤醒或到达指定的时间点”

有什么不同?将wait_until自旋,以便线程在收到信号时可以准确地(或多或少地)继续,而wait_for只是在那时将线程重新添加到调度中?

4

4 回答 4

55

不同之处在于等待持续时间的表示方式: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
于 2012-10-30T15:28:07.733 回答
33

您的问题和其他答案都重复了差异;wait_for等待指定的时间并一直wait_until等到指定的时间点,但没有说明其含义。

Atime_point有一个关联的时钟,该时钟用于确定是否到了适当的时间。这意味着该功能会考虑时钟调整wait_untilwait_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_untilsteady_clock::now() + duration.


这是标准中详细说明的部分:

[thread.req.timing] 30.2.4/2-4

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函数的时间点之间的差值的稳定时钟相对超时返回的时间。[注意:当时钟向前调整时,实现应该减少等待的持续时间。——尾注]

于 2012-10-30T15:36:46.197 回答
5
  • wait_for将等待一定的时间。例如,它将等待两秒钟。
  • wait_until将等到某个时间到达。例如,它将等到时钟到达 2013 年 7 月 23 日晚上 11:22:34。
于 2012-10-30T15:28:03.207 回答
3

正如 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_forIMO,这是一种无法轻易更换的场景wait_until,因为它具有重置性质。

于 2017-09-23T18:32:35.220 回答