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 ]