boost::this_thread::sleep()与nanosleep()有何区别?

21
我最近需要让当前线程精确地休眠一段时间。我知道在POSIX平台上有两种方法可以实现:使用nanosleep()或使用boost::this_thread::sleep()
我只是出于好奇想知道这两种方法之间的区别。它们的精度是否有差异,有没有任何不使用Boost方法的理由? nanosleep()方法:
#include <time.h>
...
struct timespec sleepTime;
struct timespec returnTime;
sleepTime.tv_sec = 0;
sleepTime.tv_nsec = 1000;
nanosleep(&sleepTime, &returnTime);

Boost方法:

#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/thread.hpp> 
...
boost::this_thread::sleep(boost::posix_time::nanoseconds(1000));

3
仅仅是一小段关于示例的注释: nanoseconds 在某些系统上不可用。使用 microseconds 更为安全。 - real4x
你可能也会对 sleep_until_ms()sleep_until_us()sleep_until_ns() 感兴趣。这些是我编写的 C and C++ 兼容的包装器,用于 clock_nanosleep()——它类似于 nanosleep(),但允许您选择要使用的时钟,例如单调时钟。clock_nanosleep(CLOCK_MONOTONIC, ...) 的默认分辨率为 55 us,如果您将 Linux 调度程序 policy 设置为 SCHED_RR 软实时轮询调度程序,并将 priority 设置为 1(最低,以避免抢占任何更高的东西),则可以将其提高到 4 us - Gabriel Staples
使用默认的SCHED_OTHER Linux调度程序,sleep_until_ms()sleep_until_us()sleep_until_ns()可靠地用于重复的周期性操作,最高可达500 Hz ~ 1 KHz,而使用SCHED_RR,您可以获得高达惊人的10 KHz ~ 100 KHz的可重复循环!(所有测试都在x86-64 CPU上运行)。请参见我在此处的答案以获取测试和详细信息,以及我的timinglib.htiminglib.c文件在我的存储库中 - Gabriel Staples
4个回答

26

我能想到为什么要使用boost的几个原因:

  • boost::this_thread::sleep()是boost.thread中的一个中断点
  • 未来,可以通过C++0x的std::this_thread::sleep_until()来替换boost::this_thread::sleep()

如果你根本没有使用线程,或者你的项目中其他所有内容都使用POSIX调用,则使用nanosleep()更为合理。

至于精度,在我的系统上,boost和nanosleep()都调用相同的系统调用hrtimer_nanosleep()。我想boost作者尝试在每个系统上获得最高精度,而对于我来说,这恰好与nanosleep()提供的相同。


6
+1 -- 值得注意的是,基于线程休眠(即使是纳秒级别的休眠)的时间控制在最好的情况下也是不可靠的。 - Billy ONeal
使用this_thread::sleep()的一个原因是它可以按照您喜欢的任何单位来延迟时间:sleep(seconds(10))sleep(nanoseconds(10))sleep(attoseconds(10))。硬件分辨率不会改变,但是无需不断引入新的睡眠API(sleepusleepnanosleep等),就可以公开提供任何可用的分辨率。 - bames53

6

你的nanosleep示例代码是错误的。

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

诚然,如果你只睡1微秒,过早醒来可能不是问题,但在一般情况下,这是完成任务的唯一途径。

更为优越的是,使用boost,boost::this_thread::sleep()是使用nanosleep()实现的。他们已经为你处理了所有疯狂的角落案例。


+1,我想到 Boost 的 sleep() 应该是使用 nanosleep() 实现的,很好得到确认。 - Justin Ardini
你在哪里看到使用nanosleep实现的sleep函数?我在thread.hpp文件中看到:inline void sleep(xtime const& abs_time) { sleep(system_time(abs_time)); } - clemahieu
@clemahieu:这不是对::sleep的调用(否则你只能以秒为单位)。这是对许多其他boost::this_thread::sleep重载之一的调用,你可以在libs/thread/src/pthread/thread.cpp中找到它的定义。 - Lightness Races in Orbit
确实需要使用while循环(或等效方式)来确保您获得完整的睡眠。对于任何想要使用clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &wakeup_time, NULL)进行强大演示的人,可以参见我的答案和代码示例,特别是以while (retcode == EINTR)开头的代码片段。 - Gabriel Staples

4

不使用Boost方法的原因是什么?

我想这很明显,唯一能想到的原因就是你需要使用boost来编译你的项目。


我想我应该说这个项目已经在使用其他的boost库了。尽管如此,这仍然是对于一般问题的一个有效回答。 - Justin Ardini

2

对我而言,使用boost variant的主要原因是跨平台。例如,如果你需要在posix和Windows平台上编译你的应用程序,那么平台自带的sleep函数就不足够了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接