What is the difference between std::condition_variable::wait_for and std::condition_variable::wait_until?
Asked Answered
L

4

41

The reference I'm using explains the two in the following way:

  • wait_for "blocks the current thread until the condition variable is woken up or after the specified timeout duration"

  • wait_until "blocks the current thread until the condition variable is woken up or until specified time point has been reached"

What is the difference? Will wait_until spin so that the thread can continue exactly (more or less) when it is signaled, whereas wait_for just adds the thread back into scheduling at that point?

Longshoreman answered 30/10, 2012 at 15:25 Comment(1)
It's the difference between point-in-time and duration. Or between location and direction, if you will.Warnock
O
65

The difference is in how the wait duration is represented: wait_for takes a relative time ("wait for up to 10 seconds"), whereas wait_until takes an absolute time ("wait until 12:00 on October 30, 2012").

Compare the declarations of the time parameters:

// wait_for:
const std::chrono::duration<Rep, Period>& rel_time

// wait_until:
const std::chrono::time_point<Clock, Duration>& abs_time
Outbrave answered 30/10, 2012 at 15:28 Comment(0)
E
33

Your question and other answers have all repeated the difference; that wait_for waits for a specified amount of time and wait_until waits until a specified point in time, but the implications are not spelled out.

A time_point has an associated clock, and that clock is what's used to determine if the appropriate time has come. That means that clock adjustments are taken into account by the wait_until function. wait_until(..., system_clock::now() + std::chrono::seconds(10)) could end up waiting an hour and 10 seconds if the clock happens to be adjusted back by an hour before the wait is up.

A duration does not have any associated clock and therefore wait_for chooses its own clock. The standard specifies that it uses std::steady_clock, which cannot be adjusted and advances at a steady rate relative to real time. This means that wait_for will wait for the specified time regardless of any adjustments made to any clocks. wait_for(..., std::chrono::seconds(10)) is guaranteed to wait 10 seconds (+ some time for the implementation to work and for scheduling issues).

There is no difference with regard to spinning vs. sleeping the thread; as wait_for is specified to behave as if it called wait_until with steady_clock::now() + duration.


Here's the part of the standard where this is spelled out:

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

2 Implementations necessarily have some delay in returning from a timeout. Any overhead in interrupt response, function return, and scheduling induces a “quality of implementation” delay, expressed as duration Di. Ideally, this delay would be zero. Further, any contention for processor and memory resources induces a “quality of management” delay, expressed as duration Dm. The delay durations may vary from timeout to timeout, but in all cases shorter is better.

3 The member functions whose names end in _for take an argument that specifies a duration. These functions produce relative timeouts. Implementations should use a steady clock to measure time for these functions. Given a duration argument Dt, the real-time duration of the timeout is Dt + Di + Dm.

4 The member functions whose names end in _until take an argument that specifies a time point. These functions produce absolute timeouts. Implementations should use the clock specified in the time point to measure time for these functions. Given a clock time point argument Ct, the clock time point of the return from timeout should be Ct + Di + Dm when the clock is not adjusted during the timeout. If the clock is adjusted to the time Ca during the timeout, the behavior should be as follows:
         — if Ca > Ct, the waiting function should wake as soon as possible, i.e. Ca + Di + Dm, since the timeout is already satisfied. [ Note: This specification may result in the total duration of the wait decreasing when measured against a steady clock. —end note ]

        — if Ca <= Ct, the waiting function should not time out until Clock::now() returns a time Cn >= Ct, i.e. waking at Ct + Di + Dm. [ Note: When the clock is adjusted backwards, this specification may result in the total duration of the wait increasing when measured against a steady clock. When the clock is adjusted forwards, this specification may result in the total duration of the wait decreasing when measured against a steady clock. —end note ]

An implementation shall return from such a timeout at any point from the time specified above to the time it would return from a steady-clock relative timeout on the difference between Ct and the time point of the call to the _until function. [ Note: Implementations should decrease the duration of the wait when the clock is adjusted forwards. —end note ]

Eternize answered 30/10, 2012 at 15:36 Comment(1)
en.cppreference.com/w/cpp/thread/condition_variable/wait_until: the existing implementations convert timeout_time from Clock to std::chrono::system_clock and delegate to POSIX pthread_cond_timedwait so that the wait honors ajustments to the system clock, but not to the the user-provided Clock.Spermatocyte
C
5
  • wait_for will wait for a certain amount of time. It will for example wait for two seconds.
  • wait_until will wait until some time is reached. It will for example wait until 23rd of July 2013 11:22:34 p.m. is reached on the clock.
Curative answered 30/10, 2012 at 15:28 Comment(0)
P
3

Here is one important difference in their usage as explained in Anthony Williams's book:

Consider this example where a condition variable is waited with a timeout:

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;
}

This is the recommended way to wait for condition variables with a time limit, if you’re not passing a predicate to the wait. This way, the overall length of the loop is bounded. As you saw in section 4.1.1, you need to loop when using condition variables if you don’t pass in the predicate, in order to handle spurious wakeups. If you use wait_for() in a loop, you might end up waiting almost the full length of time before a spurious wake, and the next time through the wait time starts again. This may repeat any number of times, making the total wait time unbounded.

IMO, this is one such scenario where wait_for can't replace wait_until so easily, because of its resetting nature.

Predesignate answered 23/9, 2017 at 18:32 Comment(1)
This is the real differenceSmokejumper

© 2022 - 2024 — McMap. All rights reserved.