最近在重读《UNIX环境高级编程》,在想linux下sleep()函数是如何实现的,他的原理是啥? 跟python time.sleep()是否一样.
首先看看linux sleep()的函数是怎么个实现方法,感觉实现起来有些下小麻烦呀.
该文章写的有些乱,欢迎来喷 ! 另外文章后续不断更新中,请到原文地址查看更新。http://xiaorui.cc/?p=3160
sleep()的实现分为三步:
1.注册一个信号signal(SIGALRM,handler)。接收内核给出的一个信号。如果不主动针对sigalrm信号处理,那么就会关闭进程的。
2.调用alarm()函数。
3.pause()挂起进程, 当你的sigalrm信号来的时候,处理信号对应函数,然后继续往下走.
具体代码实现:
#xiaorui.cc #include <stdio.h> #include <stdlib.h> #include <signal.h> #include <unistd.h> ///时钟编程 alarm() void wakeUp() { printf("please wakeup!!/n"); } int main(void) { printf("sleep! 1s /n"); signal(SIGALRM,wakeUp); alarm(1); pause(); printf("end/n"); return EXIT_SUCCESS; }
然后再strace下看看sleep()函数都干了些什么.
使用alarm函数可以设置一个计时器,在将来某个指定的时间,该计时器会超时。当计时器超时时,产生SIGALRM信号。如果不忽略或不捕捉此信号,则其默认动作是终止调用该alarm函数的进程。 pause函数使调用进程挂起直至捕捉到一个信号。
rt_sigaction(SIGALRM, {0x400594, [ALRM], SA_RESTORER|SA_RESTART, 0x3b520326a0}, {SIG_DFL, [], 0}, 8) = 0 alarm(1) = 0 pause() = ? ERESTARTNOHAND (To be restarted) --- SIGALRM (Alarm clock) @ 0 (0) --- rt_sigreturn(0) = -1 EINTR (Interrupted system call) write(1, "sleep! 1s /nplease wakeup!!/nend"..., 34sleep! 1s /nplease wakeup!!/nend/n) = 34 exit_group(0) = ?
那我们再来看看python怎么一回事. 用strace测试下面的python小脚本.
import time
print “start”
time.sleep(1)
print “end”
通过下面的strace结果已经相当的明了, 直接借助于select io多路复用模型来实现的,select一般是用来监控文件描述符变化的.
write(1, “start\n”, 6start
) = 6
select(0, NULL, NULL, NULL, {1, 0}
) = 0 (Timeout)
write(1, “end\n”, 4end
) = 4
rt_sigaction(SIGINT, {SIG_DFL, [], SA_RESTORER, 0x3df860f710}, {0x35b31033f0, [], SA_RESTORER, 0x3df860f710}, 8) = 0
exit_group(0)
再来验证下在python是不是可以直接调用select来实现sleep
In [1]: import select In [2]: select.select([], [], [], 1) Out[2]: ([], [], [])
在python的modules是看不到time的相关源码,在你编译python的时候,time模块已经被编程成so文件。
下面是python的timemodule.c源码
https://hg.python.org/cpython/file/3ae2cd85a908/Modules/timemodule.c
#xiaorui.cc floatsleep(double secs) { /* XXX Should test for MS_WINDOWS first! */ #if defined(HAVE_SELECT) && !defined(__EMX__) struct timeval t; double frac; int err; frac = fmod(secs, 1.0); secs = floor(secs); t.tv_sec = (long)secs; t.tv_usec = (long)(frac*1000000.0); Py_BEGIN_ALLOW_THREADS err = select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &t); Py_END_ALLOW_THREADS ... ... 省略
下面是select函数的具体定义.
#xiaorui.cc select.select(rlist, wlist, xlist[, timeout]) This is a straightforward interface to the Unix select() system call. The first three arguments are sequences of ‘waitable objects’: either integers representing file descriptors or objects with a parameterless method named fileno() returning such an integer: rlist: wait until ready for reading wlist: wait until ready for writing xlist: wait for an “exceptional condition” (see the manual page for what your system considers such a condition)
虽然简单说了 pyhton及c语言的sleep的实现,但这也只是语言层面的实现. 还是没有详细到系统内核方面的,看来还是需要更深层次的学习。
END.
然而,linux 下的 gnu 的 sleep 并不是用的 sigalrm,而是用的 nanosleep http://man7.org/linux/man-pages/man2/nanosleep.2.html
谢谢指点 !