Utility之定时(2)
- 2019 年 10 月 7 日
- 筆記
在《Utility之定时》里介绍了几种常见的定时机制,今天再来聊聊其它跟time有关的函数,也是可以用来定时的
- clock_gettime()
- time()
- gettimeofday()
- sigtimedwait()
- alarm()
- timer_settime()
- clock_nanosleep()
先了解几个名词
- UTC – 世界标准时间
- Epoch –一个特定时间: 1970-01-01 00:00:00 UTC
- IEEE – Institute of Electrical andElectronics Engineers,电气和电子工程师协会
- ISO – International Organization forStandardization,国际标准化组织
- IEC – International ElectrotechnicalCommission,国际电工委员会
- POSIX – Portable Operating SystemInterface。IEEE称之为IEEE 1003;ISO称之为ISO/IEC 9945
- ANSI – American National StandardsInstitute,美国国家标准学会
clock_gettime()

POSIX定义的函数clock_gettime(),用来读取当前时间
跑个例子

- 时钟CLOCK_MONOTONIC – 记录的是从系统启动到当前时刻的时长,精度由系统时钟决定
- 时钟CLOCK_PROCESS_CPUTIME_ID – 暂不支持,因此返回ERROR
- 时钟CLOCK_THREAD_CPUTIME_ID – 记录的是RTP中POSIX线程占用CPU的时长,要想测试,就得在RTP里跑一个线程

- 而时钟CLOCK_REALTIME – 记录的是从Epoch到当前时刻的时长。只不过VxWorks启动时,默认把系统时间就定义为Epoch了。所以CLOCK_REALTIME默认也就等于CLOCK_MONOTONIC了
可以使用clock_settime()修改时钟CLOCK_REALTIME。为了方便,可以通过ANSI定义的mktime()来输入我们熟悉的年月日时分秒格式;读取时,通过localtime()返回年月日时分秒

测试一下

可以看到,系统刚启动时,CLOCK_REALTIME与CLOCK_MONOTONIC相同。通过clock_settime()更新了CLOCK_REALTIME之后,它就可以表示当前时间了
不过这些都是软件层面的,如何让clock_settime()给CLOCK_REALTIME输入真正的物理时间呢?那就需要有硬件时钟的支持了,例如RTC或者Intel架构的BIOS时钟。也就是软件关机后,需要硬件来维护时间的延续
time()/gettimeofday()
还有两个函数可以用来读取CLOCK_REALTIME:time()和gettimeofday()

它俩的区别仅是精度不同: 一个是秒,一个是纳秒

这俩函数比较简单,可以轻松封装为轮询定时机制

sigtimedwait()

这个函数可以阻塞当前任务,直到收到pSet中的任一个信号(signal),或pTimeout超时
如果不给这个任务发送信号(signal),那就是表示把该任务定时到pTimeout了

alarm()

alarm()专门为信号SIGALRM而设,在指定时间(单位:秒)后,向任务本身发送SIGALRM信号。任务调用alarm()后,覆盖之前的alarm。如果参数secs为零,则取消之前的alarm。返回值是上一个alarm的剩余时间,0表示之前没有alarm

timer_settime()

这是一组函数
timer_create() – 为当前任务创建POSIX定时器
- clock_id – 指定用于测量的时钟,暂不支持CLOCK_PROCESS_CPUTIME_ID
- evp – 指定到时之后的通知方式。内核态支持两种方式: evp->sigev_notify=SIGEV_NONE: 到时之后,没有异步通知,因此只能用timer_gettime()监测;evp->sigev_notify=SIGEV_SIGNAL: 到时之后,发送signal evp->sigev_signo给该任务,使用signal()指定sigev_signo的处理函数。如果evp为NULL,则发送signal SIGALRM,并且可以使用timer_connect()指定sigev_signo的处理函数。
- pTimer – 返回新定时器的ID
timer_settime() – 启动或停止定时器timerid。定时器的时间基于timer_create()指定的时钟来测量
- value->it_value – 非0时,启动定时器(如果已经启动,则覆盖);为0时,停止定时器
- value->it_interval – 非0时,定时器周期执行,it_interval为定时间隔;为0时,定时器只执行一次,时长为it_value
- flags为0时,value->it_value表示基于时钟timerid的偏移时间。flags为TIMER_ABSTIME时,value->it_value表示基于时钟timerid的绝对时间。如果it_value不大于当时时间,函数立即返回,不阻塞当前线程。如果改变时钟CLOCK_REALTIME的时间,会影响TIMER_ABSTIME的定时器
- 如果ovalue非NULL,返回剩余时长
int timer_gettime() – 返回timerid的定时周期和剩余时长,不管是不是TIMER_ABSTIME
- 如果value->it_value返回0,表示定时器已经关闭
- 如果value->it_interval返回0,表示是单发定时器
timer_delete() – 先停止timerid,然后删除
跑个例子

把timer_connect()换成signal()的话,可以使用更多的signal number,不过参数就少了一个

clock_nanosleep()

这个clock_nanosleep()与之前介绍的nanosleep()比较像,底层也用到了taskDelay(),不过功能更强大
- clock_id – 支持两种时钟CLOCK_REALTIME、CLOCK_MONOTONIC
- flags – 支持两种模式 TIMER_ABSTIME、TIMER_RELTIME
- rqtp – 为0时,立即返回。TIMER_RELTIME模式下,以时钟clock_id为基准,sleep时长为rqtp。TIMER_ABSTIME模式下,sleep到时钟clock_id运行到rqtp为止;如果rqtp不晚于当前时间,则立即返回
- rmtp – 如果任务因为signal而提前返回,且不是TIMER_ABSTIME模式,rmtp非NULL时,存储剩余时长

对比一下

你还知道哪些定时机制?
这正是:
定时机制有多种,各个标准皆不同。
根据需求来调用,定时精度靠时钟。