本文主要介绍Linux下高精度时间函数,及相关的具有超时机制的函数,对定时器也进行简单的介绍。
在linux下通常可用的精度最高的时间接口是gettimeofday,它返回一个timeval结构,其精度为us,即10-6 秒,大多数情况这个精度已经够用了。不过有时为了更高的精度,比如纳秒级的时间精度,我们需求探索Linux为我们提供的时间调用。
首先介绍struct timespec结构,这个结构体有两个成员,一个是秒,一个是纳秒。
在librt库中,提供了高精度的时间函数,分别是:
long clock_gettime(clockid_t ,struct timespec*) |
获取特定时钟的时间,时间通过fp结构传回,目前定义了6种时钟,分别是
CLOCK_REALTIME 系统当前时间,从1970年1.1日算起 CLOCK_MONOTONIC 系统的启动时间,不能被设置 CLOCK_PROCESS_CPUTIME_ID 进程运行时间 CLOCK_THREAD_CPUTIME_ID 线程运行时间 CLOCK_REALTIME_HR CLOCK_REALTIME的高精度版本 CLOCK_MONOTONIC_HR CLOCK_MONOTONIC的高精度版本 |
获取特定时钟的时间精度:
long clock_getres(clockid_t ) |
设置特定时钟的时间:
long clock_settime(clockid_t ,struct timespec*) |
休眠time中指定的时间,如果遇到信号中断而提前返回,则由left_time返回剩余的时间:
long clock_nanosleep(clockid_t ,int flag,timespec* time,timespec* left_time) |
有了这些个时间函数之后,我们再来看下如何实现一些不同精度的简单的定时器。
最粗糙的定时器可以由sleep来实现,其精度为秒级,系统也提供像nanosleep,usleep,ualarm等,当然你愿意也可以由poll(ms)、select(us)、ppoll或pslect(ns)等来实现各种精度的sleep。通过这些高精度的sleep函数,也可以实现一系统不同精度的定时器。
通过上述sleep实现的定时器通常需要我们自行进行编码,而且过多的sleep也会导致某个cpu不能充分的利用,对于大量定时器的场合就需要小心编写代码,这种方式通常以单独线程控制或主循环轮询的方式查看哪些定时器到期。总体来说,实现复杂,效率较低,而且也没有一种好的定时器到期时的通知机制,通常是被动由定时器线程强行执行或者自身线程在线程主循环中检查到期的定时器并执行。
下面我们将探索一下由操作系统提供的一些定时器机制。操作系统提供了两个种类的定时器,一种是显式的定时器,另一种是隐藏在调用的超时时间或特定文件属性之上。后者我们在前面已经见到过,比如select、套接字描述符的超时属性,这些需要在不同的编程领域去积累,当然它们也有各自的精度。下面我们主要介绍一下系统提供的显式的定时器。
Linux系统为每个进程提供了三个间隔定时器,精度为us。定时器到期时将触发相应的信号,定时器可能会重新开始,值得注意的是,fork生成的子进程并不继承父进程的定时器。