小言_互联网的博客

Linux实现进程睡眠/延时/暂停(sleep/usleep/nanosleep命令的用法和对比)

1184人阅读  评论(0)

Linux下用过两种命令实现延时,分别是sleepusleep;文中提到的nanosleep是C函数,目前shell解释器好像不支持、命令行中无法调用。

sleep

sleep n[unit]n为暂停的时长,unit为暂停的时间单位。

单位支持多种:秒、分、时、天

# 睡眠1秒
sleep 1s
# 睡眠1分
sleep 1m
# 睡眠1小时 
sleep 1h
# 睡眠1天
sleep 1d

注意:

  • 默认单位为秒,即sleep 1等价于sleep 1s
  • n支持小数,如sleep 0.1表示延迟100毫秒

usleep

sleep用法类似,但只支持一个单位:微秒。
usleep 1000表示1毫秒(单位换算参见附1)。

POSIX.1-2001已将usleep标注为废弃,POSIX.1-2008已删除usleep,应当使用nanosleep替代usleep
在Solaris的多线程环境下编译器会自动把usleep()连接成nanosleep()

nanosleep

精度是纳秒级。

nanosleep是C函数,命令行不支持调用。

总结

  • 一般情况下,延迟时间数量级是秒的时候,尽可能使用sleep()函数。
  • 如果延迟时间为几十毫秒(1ms = 1000us),或者更小,尽可能使用usleep()函数。这样才能最佳的利用CPU时间
  • 原则上sleep()usleep()都已废弃,函数调用时建议采用nanosleep()

三种命令的总结对比如下:

sleep usleep nanosleep
支持的单位 秒/分/时/天 微秒 纳秒
是否精确(见附3) 不精确 不精确
具体偏差视系统调度间隔而定,一般为10ms
不精确
线程安全 在一些平台下不是线程安全,如HP-UX以及Linux
信号安全 不能和alarm同时使用 不确定
暂停效果与恢复 令目前的进程暂停,直到达到参数seconds 所指定的时间,或是被信号所中断
底层实现(见附2) sleep()非系统调用,sleep()是在库函数中实现的,它是通过alarm()来设定报警时间,使用sigsuspend()将进程挂起在信号SIGALARM上 库函数中实现 Linux中的系统调用,它是使用定时器来实现的,该调用使调用进程睡眠,并往定时器队列上加入一个timer_list型定时器,time_list结构里包括唤醒时间以及唤醒后执行的函数,通过nanosleep()加入的定时器的执行函数仅仅完成唤醒当前进程的功能。系统通过一定的机制定时检查这些队列(比如通过系统调用陷入核心后,从核心返回用户态前,要检查当前进程的时间片是否已经耗尽,如果是则调用schedule()函数重新调度,该函数中就会检查定时器队列,另外慢中断返回前也会做此检查),如果定时时间已超过,则执行定时器指定的函数唤醒调用进程。当然,由于系统时间片可能丢失,所以nanosleep()精度也不是很高
windows是否支持
unistd.h是UNIX系统标准头文件,用于系统调用,相当于win32中的windows.h,unistd.h定义的函数只能用于UNIX环境中,而不能用于windows

nalosleep 和其它时间日期操作函数,都是定义在time.h中的,所以Windows支持
其他说明 unsigned int sleep(unsigned int seconds);
若进程暂停到参数seconds 所指定的时间,成功则返回0,若有信号中断则返回剩余秒数。
unsigned int usleep(unsigned int useconds);
除了时间单位为微秒以外,在使用上与sleep()差不多。还有就是实现也是不同的,sleep因为是用alarm实现的,所以时间单位为s ,而usleep的时间单位为us,那肯定不是由alarm实现的,所以说它们的实现不同,但都是linux用的,而window下不能用,因为都是sleep和usleep都是在unistd.h下定义的。return:若进程暂停到参数seconds 所指定的时间,成功则返回0,若有信号中断则返回剩余微秒数。
这个函数功能是暂停某个进程直到你规定的时间后恢复,参数req就是你要暂停的时间,其中req->tv_sec是以秒为单位,而tv_nsec以毫微秒为单位(10的-9次方秒)。由于调用nanosleep是是进程进入TASK_INTERRUPTIBLE,这种状态是会相应信号而进入TASK_RUNNING状态的,这就意味着有可能会没有等到你规定的时间就因为其它信号而唤醒,此时函数返回-1,切还剩余的时间会被记录在rem中。
return: 若进程暂停到参数req所指定的时间,成功则返回0,若有信号中断则返回-1,并且将剩余微秒数记录在rem中。

上面这些基本上说清楚命令的使用了,如果要了解底层原理,可以参考这篇文章:《Linux中延时/暂停函数(sleep/usleep/nanosleep/select)的比较、底层实现说明》《Linux 高精確的時序(sleep, usleep,nanosleep)》


附1: 单位换算
中文名 英文名 英文缩写 换算
second s 1000ms
毫秒 millisecond ms 1000μs
微妙 microsecond μs 1000ns
纳秒 nanosecond ns 1000ps
皮秒 picosecond ps

附2:命令系统实现代码摘录
sleep()-------以秒为单位
#include<unistd.h>
unsigned int sleep(unsigned int seconds);
return:若进程暂停到参数seconds 所指定的时间,成功则返回0,若有信号中断则返回剩余秒数。
在linux中,sleep是通过nanosleep实现的。在一些其他系统中(例如POSIX.1),它是通过alarm()来实现的。

usleep()----以微秒为单位
#include<unistd.h>
unsigned int usleep(unsigned int useconds);
return:若进程暂停到参数seconds 所指定的时间,成功则返回0,若有信号中断则返回剩余微秒数。

nanosleep( )---------以纳秒为单位
#include<time.h>
 struct timespec
{
  time_t  tv_sec;         /* 秒seconds */
  long    tv_nsec;        /* 纳秒nanoseconds */
};
int nanosleep(const struct timespec *req, struct timespec *rem);
return: 若进程暂停到参数*req所指定的时间,成功则返回0,若有信号中断则返回-1,并且将剩余微秒数记录在*rem中。
req->tv_sec是以秒为单位,而tv_nsec以毫微秒为单位(10-9次方秒)。
由于调用nanosleep是是进程进入TASK_INTERRUPTIBLE,这种状态是会相应信号而进入TASK_RUNNING状态的。

附3:精确度

与系统时钟关系(线程调度间隔):
我们假设时钟中断是10纳秒一次,如果tv_sec = 0, tv_nsec = 2,那么时钟中断一定是在10纳秒后来唤醒这个进程的,这里我们看到任务的重新调度最少是在10纳秒之上,因此此函数的精确程度与时钟频率有关系。
cpu的速度决定了时钟周期; 如, 一個 50 MHz 的CPU, 一個时钟周期的时间是 1/50000000 s(200 nsec)。

参考《深入理解linux下的短延迟:nanosleep,sleep》


以上。感谢您的阅读。


转载:https://blog.csdn.net/zgdwxp/article/details/100767097
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场