I have the following code (hand-copied in):
// Simple stop watch class basically takes "now" as the start time and
// returns the diff when asked for.
class stop_watch {...}
// global var
std::thread timer_thread;
void start_timer(int timeout_ms)
{
timer_thread = std::thread([timeout_ms, this](){
stop_watch sw;
while (sw.get_elapsed_time() < timeout_ms)
{
// Here is the sleep to stop from hammering a CPU
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
// Do timeout things here...
std::cout << "timed out!" << std::endl;
})
}
I did not want to get too bogged down in the detail of the class I writing so this is a very cut-down version. The full class calls a function call-back and has a variable to cancel the timer etc...
I just wanted to focus on the "sleep" part. Can I implement something like this without a sleep or is there a better way to do it? - or is sleep perfectly good? - I was of the opinion that sleeps are generally a sign of bad design (I have read that a few places)... but I can't think of a way to implement a timer without one :(
Additional Note: The timer should have the requirement to be able to be stopped/woken at any time. Just adding that for clarity because it appears to affect what kind of solution to go for. In my original code (not this snippet) I used an atomic bool flag that can break out of the loop.
C++11 provides us with
std::condition_variable
. In your timer you can wait until your condition has been met: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:
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 callssleep_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 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.
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 usingsleep
orthis_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
orstd::this_thread::sleep_until
are your best bet. These are defined in standard header<thread>
.sleep(3)
is a POSIX function (likenanosleep
), 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.)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)
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 thansteady_clock
.Sleep gotchas: late / early wakeup
The caveats about possibly sleeping too long also apply to
sleep
andnanosleep
, 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 usesleep_until
)