Can you implement a timer without a "sleep" in it using standard c++/c++11 only?
C++11 provides us with std::condition_variable
. In your timer you can wait until your condition has been met:
// Somewhere else, e.g. in a header:
std::mutex mutex;
bool condition_to_be_met{false};
std::condition_variable cv;
// In your timer:
// ...
std::unique_lock<std::mutex> lock{mutex};
if(!cv.wait_for(lock, std::chrono::milliseconds{timeout_ms}, [this]{return condition_to_be_met;}))
std::cout << "timed out!" << std::endl;
You can find more information here: https://en.cppreference.com/w/cpp/thread/condition_variable
To signal that the condition has been met do this in another thread:
{
std::lock_guard<std::mutex> lock{mutex}; // Same instance as above!
condition_to_be_met = true;
}
cv.notify_one();
While your code will "work", it is sub-optimal for the intended purpose as timer.
There exists std::this_thread::sleep_until
which, depending on the implementation, possibly only just calls sleep_for
after doing some math anyway, but which might use a proper timer, which is vastly superior in terms of precision and reliability.
Generally, sleeping is not the best, most reliable, and most accurate thing to do, but sometimes, if just waiting for some approximate time is what's intended, it can be "good enough".
In any case, repeatedly sleeping for small amounts as in your example is a bad idea. This will burn a lot of CPU on needlessly rescheduling and waking threads, and on some systems (Windows in particular, though Windows 10 isn't so bad in that respect any more) it may add a considerable amount of jitter and uncertainity. Note that different Windows versions round to the scheduler's granularity differently, so in addition to generally being not overly precise, you do not even have consistent behavior. Rounding is pretty much "who cares" for a single large wait, but it is a serious problem for a series of small waits.
Unless the ability to abort the timer prematurely is a necessity (but in that case, there are better ways of implementing that, too!), you should sleep exactly once, never more, for the full duration. For correctness you should then check that you indeed got the time you expected because some systems (POSIX, notably) may under-sleep.
Over-sleeping is a different problem if you need it right, because even if you check and detect that case correctly, once it has happened there's nothing you can do about it (time has already passed, and never comes back). But alas, that's just a fundamental weakness of sleeping, not much you can do. Luckily, most people can shrug this problem off, most of the time.
You could busy-wait checking the time in a loop, until it reaches the time you're waiting for. That's obviously horrible, so don't do it. Sleeping for 10ms is somewhat better, but definitely poor design. (@Damon's answer has some good info.)
There's nothing wrong with using functions with sleep
in their name if that's the most useful thing for your program to do right then.
The suggestion to avoid sleep
is probably recommending against the general pattern of sleeping for a short time, checking if there's anything to do, then sleeping again. Instead, block waiting for an event with no timeout, or a very long timeout. (e.g. a GUI should wait for a keypress / click by calling a blocking function, with a timeout set to wake it up when it's time to autosave or whatever future thing is coming up next. You normally don't need a separate thread just to sleep, but you might if there's nowhere sensible to insert checks for the current time.)
Letting the OS wake you up when it's finally time to do anything is much better. This avoids context switches and cache pollution slowing down other programs and wasting power while you're spinning on short sleeps.
If you know there's nothing to do for some time, just sleep for that long with a single sleep. AFAIK, multiple short sleeps won't improve the accuracy of the wake-up time on mainstream OSes like Windows, Linux, or OS X. You might avoid an instruction-cache miss if your code had been waking up frequently, but if that amount of delay is a real problem you probably need a real-time OS and a much more sophisticated approach to timing. (Like wake up a fraction of a second early and spin-wait from there.)
If anything, a thread that's been sleeping for a long time is more likely to wake up exactly when it requested, while a thread that was running recently and slept for only 10ms might run into scheduler timeslice issues. On Linux, threads that have been asleep for a while get a priority boost when they do wake up.
Using a function without sleep
in the name that blocks for 1 second is no better than using sleep
or this_thread::sleep_for
.
(Apparently you want another thread to be able to wake you up. This requirement is buried in the question, but yes a condition variable is a good portable way to do that.)
If you want to use pure ISO C++11, then std::this_thread::sleep_for
or std::this_thread::sleep_until
are your best bet. These are defined in standard header <thread>
.
sleep(3)
is a POSIX function (like nanosleep
), not part of ISO C++11. If that's not a problem for you, then feel free to use it if it's appropriate.
For portable high-precision OS-assisted sleep-for-an-interval, C++11 introduced
std::this_thread::sleep_for(const std::chrono::duration<Rep, Period> &sleep_duration)
(The cppreference page has a code example of using it.)
Blocks the execution of the current thread for at least the specified sleep_duration.
This function may block for longer than sleep_duration due to scheduling or resource contention delays.
The standard recommends that a steady clock is used to measure the duration. If an implementation uses a system clock instead, the wait time may also be sensitive to clock adjustments.
To sleep until a clock reaches a specified time (possibly taking into account changes / corrections to the system time):
std::this_thread::sleep_until(const std::chrono::time_point<Clock,Duration>& sleep_time)
Blocks the execution of the current thread until specified
sleep_time
has been reached.The clock tied to
sleep_time
is used, which means that adjustments of the clock are taken into account. Thus, the duration of the block might, but might not, be less or more thansleep_time - Clock::now()
at the time of the call, depending on the direction of the adjustment. The function also may block for longer than until aftersleep_time
has been reached due to scheduling or resource contention delays.
Notice that sleep_for
is meant to be unaffected by changes to the system clock, so it sleeps for that much real time.
But sleep_until
is supposed to let you wake up when the system clock reaches a given time, even if it did that by being adjusted (NTP or manual setting), if used with a clock other than steady_clock
.
Sleep gotchas: late / early wakeup
The caveats about possibly sleeping too long also apply to sleep
and nanosleep
, or any other OS-specific sleep or timeout (including the condition-variable approach in @Sebastian's answer), of course. It's unavoidable; a realtime OS can give you upper bounds on that extra delay, though.
You're already doing something like this with your 10ms sleeps:
Always assume that sleep
or whatever other function woke up late, and check the current time instead of using dead-reckoning in any case where that matters.
You can't build a reliable clock out of repeated sleep
.
e.g. don't build a count-down timer that sleeps for 1 second, decrements and displays a counter, then sleeps for another second. Unless it's just a toy and you don't care much about accuracy.
Some sleep functions such as POSIX sleep(3)
can also wake up early on a signal. If waking too early is a correctness problem, check the time and if necessary go back to sleep for the calculated interval. (Or use sleep_until
)