C语言中的usleep()函数是实现为忙等待吗?

18

我正在使用pthreads构建一个多线程应用程序,并需要一个线程定期检查一些内容。在此期间,该线程不应使用任何CPU资源。使用usleep()函数可以实现吗? usleep()是否会进行忙等待?还是有更好的解决方案?


1
我认为pthread有一个yield()功能可能会很有用。 - Kerrek SB
2
usleep与C语言无关,它是操作系统的一个功能。 - Jens Gustedt
@KerrekSB: pthread_yield 不会降低 CPU 使用率,它只会导致线程相对于同一优先级级别的其他线程被暂时降低优先级。 - Dietrich Epp
5个回答

16

usleep函数已从SUSv4中删除。你应该使用nanosleep或者计时器(setitimer,等)。

正如R..在评论中指出的那样,如果将休眠实现为忙等待:

  • 线程将继续使用CPU
  • 其他(优先级较低的)线程将无法运行

因此:

  • 一些人可能使用信号(I think SUSv3 mentioned SIGALARM?)
  • 一些人可能使用高级计时器(fancy timers)

1
这是标准的,但符合POSIX :) - Jens Gustedt
好的,我原以为它只是被弃用了,我会修改我的回答。 - Jens Gustedt
1
@JensGustedt kernel.org提到它不在SUSv4中。在SUSv4中搜索它没有结果。 - cnicutar
1
它不能被实现为繁忙等待,因为那样会排斥其他低优先级的线程/进程运行。 - R.. GitHub STOP HELPING ICE
@R.. 我会把这个加入到我的回答中 :-) - cnicutar
显示剩余2条评论

12

(usleep不是C标准的一部分,而是古老的POSIX标准的一部分。但请参见下文。)

不,usleep的POSIX规范明确指出

usleep()函数将导致调用线程暂停执行...

因此,这显然需要它暂停执行并让资源给其他进程或线程。

正如其他人已经提到的,POSIX函数nanosleep现在正在取代usleep,你应该使用它。C(自C11)有一个函数thrd_sleep,它是模拟nanosleep


7
请注意,usleep()和nanosleep()都可能会被信号中断。 nanosleep()允许您传递一个额外的timespec指针,如果发生中断,则会将剩余时间存储在其中。因此,如果您确实需要保证延迟时间,您可能需要编写一个简单的nanosleep()包装器。
请注意,这未经过测试,但大致如下:
int myNanoSleep(time_t sec, long nanosec)
{
   /* Setup timespec */
   struct timespec req;
   req.tv_sec = sec;
   req.tv_nsec = nanosec;

   /* Loop until we've slept long enough */
   do 
   {
      /* Store remainder back on top of the original required time */
      if( 0 != nanosleep( &req, &req ) )
      {
          /* If any error other than a signal interrupt occurs, return an error */
          if(errno != EINTR)
             return -1; 
      }
      else
      {
          /* nanosleep succeeded, so exit the loop */
          break;
      }
   } while( req.tv_sec > 0 || req.tv_nsec > 0 )
   return 0; /* Return success */
}

如果您需要唤醒线程进行周期性超时以外的其他操作,请查看条件变量和 pthread_cond_timedwait()


这一直让人感到有趣,因为在 POSIX 的 sleep 函数中,请求的时间不仅不是一个上限(因为像其他操作系统一样,系统可以自由地重新安排您的线程),而且由于信号的存在,甚至不是一个下限。基本上,类似 sleep 的函数可以在它们最喜欢的任何时候返回。:-D - Matteo Italia

5
在Linux系统中,它使用不是忙等待的nanosleep系统调用实现。使用strace,我可以看到对usleep(1)的调用被转换为nanosleep({0, 1000}, NULL)。请注意,HTML标签已保留,请勿进行任何更改。

1

usleep()是一个基于系统计时器构建的C运行库函数。
nanosleep()是一个系统调用。

仅MS-DOS和类似的操作系统将sleep函数实现为繁忙等待。任何实际提供多任务处理的操作系统都可以通过协调任务和进程的机制轻松提供睡眠功能。


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