21

I recently came across the need to sleep the current thread for an exact period of time. I know of two methods of doing so on a POSIX platform: using nanosleep() or using boost::this_thread::sleep().

Out of curiosity more than anything else, I was wondering what the differences are between the two approaches. Is there any difference in precision, and is there any reason not to use the Boost approach?

nanosleep() approach:

#include <time.h>
...
struct timespec sleepTime;
struct timespec returnTime;
sleepTime.tv_sec = 0;
sleepTime.tv_nsec = 1000;
nanosleep(&sleepTime, &returnTime);

Boost approach:

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp> 
...
boost::this_thread::sleep(boost::posix_time::nanoseconds(1000));
sergtk
  • 10,714
  • 15
  • 75
  • 130
Justin Ardini
  • 9,768
  • 2
  • 39
  • 46
  • 3
    Just a small note to the example: `nanoseconds` is not available on all the systems. Using of `microseconds` would be more safe. – real4x Jan 27 '13 at 02:28
  • (1/2) You may be interested in `sleep_until_ms()`, `sleep_until_us()`, and `sleep_until_ns()`, as well. These are **C _and_ C++-compatible** wrappers I wrote around `clock_nanosleep()`--which is like `nanosleep()` except it allows you to choose the clock to use, such as a monotonic clock. `clock_nanosleep(CLOCK_MONOTONIC, ...)` has a default resolution of **55 us**, and can be improved to **4 us** if you set the Linux scheduler `policy` to the `SCHED_RR` soft real-time round-robin scheduler, with a `priority` of `1` (the lowest, so as to not preempt anything higher). – Gabriel Staples Apr 12 '22 at 22:51
  • (2/2) With the default `SCHED_OTHER` Linux scheduler, `sleep_until_ms()`, `sleep_until_us()`, and `sleep_until_ns()` are reliable for repeated, periodic actions up to **500 Hz ~ 1 KHz**, and with `SCHED_RR` you can get repeatable loops up to an incredibly fast **10 KHz ~ 100 KHz**!--(all tests run on x86-64 cpu). [See my answer here for testing & details](https://stackoverflow.com/a/71790209/4561887), and my `timinglib.h` and `timinglib.c` [files in my repo here](https://github.com/ElectricRCAircraftGuy/eRCaGuy_hello_world/tree/master/c). – Gabriel Staples Apr 12 '22 at 22:51

4 Answers4

26

The few reasons why use boost that I can think of:

  • boost::this_thread::sleep() is an interruption point in boost.thread
  • boost::this_thread::sleep() can be drop-in replaced by C++0x's std::this_thread::sleep_until() in future

For why not -- if you're not using threads at all, or of everything else in your project uses POSIX calls, then nanosleep() makes more sense.

As for precision, on my system both boost and nanosleep() call the same system call, hrtimer_nanosleep(). I imagine boost authors try to get the highest precision possible on each system and for me it happens to be the same thing as what nanosleep() provides.

Cubbi
  • 46,567
  • 13
  • 103
  • 169
  • 6
    +1 -- it should be noted that timing based upon thread sleeps -- even nanosleep -- is unreliable at best. – Billy ONeal Jun 18 '10 at 21:12
  • One reason to use `this_thread::sleep()` is because it takes time in whatever units you like: `sleep(seconds(10))`, `sleep(nanoseconds(10))`, `sleep(attoseconds(10))`. The hardware resolution doesn't change, but whatever resolution is offered can be exposed without any need to keep introducing new sleep APIs (`sleep`, `usleep`, `nanosleep`, etc.). – bames53 Aug 25 '14 at 22:08
6

How about because your nanonsleep example is wrong.

#include <time.h>
...
struct timespec sleepTime;
struct timespec time_left_to_sleep;
sleepTime.tv_sec = 0;
sleepTime.tv_nsec = 1000;
while( (sleepTime.tv_sec + sleepTime.tv_nsec) > 0 )
{
   nanosleep(&sleepTime, &time_left_to_sleep);
   sleepTime.tv_sec = time_left_to_sleep.tv_sec;
   sleepTime.tv_nsec = time_left_to_sleep.tv_nsec;
}

Admittedly if you're only sleeping for 1 microsecond waking up too early shouldn't be an issue, but in the general case this is the only way to get it done.

And just to ice the cake in boost's favor, boost::this_thread::sleep() is implemented using nanosleep(). They just took care of all the insane corner cases for you.

hlovdal
  • 26,565
  • 10
  • 94
  • 165
deft_code
  • 57,255
  • 29
  • 141
  • 224
  • +1, I figured that boost `sleep()` would be implemented with `nanosleep()`, good to have confirmation. – Justin Ardini Jun 18 '10 at 22:15
  • Where do you see sleep implemented with nanosleep? In thread.hpp I'm seeing: inline void sleep(xtime const& abs_time) { sleep(system_time(abs_time)); } – clemahieu Jul 19 '11 at 15:52
  • @clemahieu: That's not a call to `::sleep` (otherwise you'd be limited to seconds resolution). It's a call to one of the many other `boost::this_thread::sleep` overloads, whose definition you may find in `libs/thread/src/pthread/thread.cpp`. – Lightness Races in Orbit Dec 18 '15 at 13:51
  • It is true you have to use a `while` loop (or equivalent) to ensure you get the full sleep. For anyone looking for a robust demonstration of doing this with `clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &wakeup_time, NULL)` instead, with the `TIMER_ABSTIME` flag for absolute timestamps, see [my answer and code examples here](https://stackoverflow.com/a/71790209/4561887), in particular the code snippet starting with `while (retcode == EINTR)`. – Gabriel Staples Apr 12 '22 at 23:01
4

is there any reason not to use the Boost approach

I suppose this is kind of obvious, but the only reason I can think of is that you'd require boost to compile your project.

Billy ONeal
  • 104,103
  • 58
  • 317
  • 552
  • I suppose I should have said the project already uses other boost libraries. Nonetheless, a valid answer to the general question. – Justin Ardini Jun 18 '10 at 22:13
2

For me the main reason for using the boost variant is platform independence. If you are required to compile your application for both posix and Windows platforms, for example, the platform sleep is not sufficient.

MM.
  • 4,224
  • 5
  • 37
  • 74