睡眠/纳米睡眠是否通过忙碌的等待计划工作?

我想知道内部如何实现睡眠/纳米睡眠? 考虑以下代码:

{ // on a thread other than main() thread while(1) { //do something sleep(1); } } 

CPU是否会进行恒定的上下文切换以检查是否完成了1秒的睡眠(即内部忙等待)。

我怀疑这种方式是否有效,效率太低。 但那又如何运作?

同样的问题适用于nanosleep。

注意:如果这是特定于实现/操作系统的,那么我怎样才能实现一个不会导致上下文切换的更有效的方案呢?

这里不保证确切的实现,但你可以期待一些属性。

通常sleep (3)是非常不准确的,因为Linux’人睡眠3’状态甚至可以使用SIGALM (信号)实现。 所以绝对不是性能。 它绝对不是关于旋转锁,所以不能是CPU密集型。

nanosleep是完全不同的动物,即使使用自旋锁也可以实现。 哪个更重要,至少在Linux nanosleep man中是第2节,它是系统调用,所以至少它应该包括切换到内核模式。 你真的需要它的高分辨率吗?

UPDATE

当我看到你的评论时,我建议select()用作man select 3状态:

  #include  #include  #include  #include  #include  int main(void) { fd_set rfds; struct timeval tv; int retval; /* Watch stdin (fd 0) to see when it has input. */ FD_ZERO(&rfds); FD_SET(0, &rfds); /* Wait up to five seconds. */ tv.tv_sec = 5; tv.tv_usec = 0; retval = select(1, &rfds, NULL, NULL, &tv); /* Don't rely on the value of tv now! */ if (retval == -1) perror("select()"); else if (retval) printf("Data is available now.\n"); /* FD_ISSET(0, &rfds) will be true. */ else printf("No data within five seconds.\n"); exit(EXIT_SUCCESS); } 

如果您需要在某个事件的线程中睡眠,并且此事件可以链接到文件描述符,那么它是经过validation的机制。

实现sleep()nanosleep()的典型方法是将参数转换为OS调度程序使用的任何比例(在向上舍nanosleep()并将当前时间添加到它以形成“绝对唤醒时间”; 然后告诉调度程序在达到“绝对唤醒时间”之前不要给线程CPU时间。 没有繁忙的等待。

请注意,OS调度程序使用的任何比例通常取决于可用的硬件和/或用于保持时间的硬件。 它可以小于纳秒(例如,在“TSC截止模式”中使用的80×86上的本地APIC)或大至100毫秒。

另请注意,操作系统保证延迟不会低于您的要求; 但是通常不能保证它不会更长,并且在某些情况下(例如,在高负载系统上的低优先级线程),延迟可能比请求的要大得多。 例如,如果要求睡眠时间为123纳秒,那么在调度程序确定它可以为您提供CPU时间之前,您可能会睡眠2毫秒,然后在调度程序确实为您提供CPU时间之前它可能是另一个500毫秒(例如,因为其他线程正在使用CPU)。

一些操作系统可能会尝试减少这种“比请求时间长得多”的问题,并且一些操作系统(例如,设计用于硬实时)可能提供某种保证(具有限制 – 例如受线程优先级限制)延迟之间的最短时间到期并恢复CPU。 要做到这一点,操作系统/内核会将参数转换为操作系统调度程序使用的任何比例(在向下舍入而不是向上舍入的情况下),并且可以减去一小部分“以防万一”; 这样调度程序就会在请求的延迟到期之前唤醒线程(而不是之后); 然后当线程被给予CPU时间时(在上下文切换到线程的成本之后,并且可能在预取各种高速缓存行之后线程被保证使用),内核将忙于等待直到延迟实际到期。 这允许内核将控制权传递回非常接近延迟到期的线程。

例如,如果你要求hibernate123纳秒,那么调度程序可能不会给你100纳秒的CPU时间,那么它可能花费10纳秒切换到你的线程,然后它可能忙等待剩余的13纳秒。 即使在这种情况下(忙碌等待完成),它通常也不会忙于等待延迟的整个持续时间。 但是,如果延迟非常短,内核只会进行最后的繁忙等待。

最后,有一个特殊情况值得一提。 在POSIX系统上sleep(0); 通常被滥用为yield() 。 我不太确定这种做法是多么合理 – 调度程序不可能支持yield()类的东西,除非调度程序愿意在更重要的工作等待时浪费CPU时间做不重要的工作。

sleepnanosleep sleep的POSIX规范说(强调我的)

sleep()函数将导致调用线程暂停执行,直到参数seconds指定的实时秒数已经过去或者信号被传递给调用线程并且其操作是调用信号捕获函数或终止进程。 由于系统安排其他活动,暂停时间可能比请求的时间长。

(来源: http : //pubs.opengroup.org/onlinepubs/9699919799/functions/sleep.html 。)

nanosleep()函数将导致当前线程暂停执行,直到rqtp参数指定的时间间隔已经过去或者信号被传递给调用线程,并且其操作是调用信号捕获函数或者终止进程。 暂停时间可能比请求的时间长,因为参数值被舍入到睡眠分辨率的整数倍或者由于系统调度其他活动。 但是,除了被信号中断的情况外,暂停时间不应小于rqtp规定的时间,由系统时钟CLOCK_REALTIME测量。

(来源: http : //pubs.opengroup.org/onlinepubs/9699919799/functions/nanosleep.html 。)

我读到这一点,说POSIX兼容的系统不能使用繁忙的循环进行sleepnanosleep sleep 。 调用线程需要暂停执行。

“我想知道内部如何实现睡眠/纳米睡眠?”

它没有一个实现,但是每个OS和POSIX兼容的sleep()nanosleep()都是免费的,它们实际上是如何实现这个function的。

因此,在没有特定OS / POSIX库实现的更多上下文的情况下,询问它实际上是如何完成的是非常无用的。