Timer
高精度定时器 posix_timer
创建、初始化以及删除一个定时器的行动被分为三个不同的函数:timer_create()(创建定时器)、timer_settime()(初始化定时器) 以及timer_delete()(销毁它)。
创建
进程可以通过调用 timer_create() 创建特定的定时器,定时器是每个进程自己的,不是在 fork 时继承的。
1 | int timer_create(clockid_t clock_id, struct sigevent *evp, timer_t *timerid) |
参数
clock_id
clock_id 说明定时器是基于哪个时钟的1
2
3
4
5
6CLOCK_REALTIME :Systemwide realtime clock.
CLOCK_MONOTONIC:Represents monotonic time. Cannot be set. monotonic:单调的无变化的
CLOCK_PROCESS_CPUTIME_ID :High resolution per-process timer. 高分辨率
CLOCK_THREAD_CPUTIME_ID :Thread-specific timer.
CLOCK_REALTIME_HR :High resolution version of CLOCK_REALTIME.
CLOCK_MONOTONIC_HR :High resolution version of CLOCK_MONOTONIC.timerid
装载的是被创建的定时器的 ID。该函数创建了定时器,并将他的 ID 放入 timerid 指向的位置中。sigevent:evp
参数 evp 指定了定时器到期要产生的异步通知。
如果 evp 为 NULL,那么定时器到期会产生默认的信号,对 CLOCK_REALTIMER 来说,默认信号就是 SIGALRM。
如果要产生除默认信号之外的其它信号,程序必须将 evp->sigev_signo 设置为期望的信号码。
struct sigevent 结构中的成员 evp->sigev_notify 说明了定时器到期时应该采取的行动。通常,这个成员的值为 SIGEV_SIGNAL, 这个值说明在定时器到期时,会产生一个信号。程序可以将成员 evp->sigev_notify 设为 SIGEV_NONE 来防止定时器到期时产生信号。
如果几个定时器产生了同一个信号,处理程序可以用 evp->sigev_value 来区分是哪个定时器产生了信号。要实现这种功能,程序必须在为信号安装处理程序时,使用 struct sigaction 的成员 sa_flags 中的标志符 SA_SIGINFO。
sigevent
1 | struct sigevent { |
通过将 evp->sigev_notify 设定为如下值来定制定时器到期后的行为:
SIGEV_NONE:什么都不做,只提供通过
timer_gettime和timer_getoverrun查询超时信息。SIGEV_SIGNAL: 当定时器到期,内核会将
sigev_signo所指定的信号传送给进程。在信号处理程序中,si_value会被设定会sigev_value。SIGEV_THREAD: 当定时器到期,内核会 (在此进程内) 以
sigev_notification_attributes为线程属性创建一个线程,并且让它执行sigev_notify_function,传入sigev_value作为为一个参数。
启动
timer_create() 所创建的定时器并未启动。要将它关联到一个到期时间以及启动时钟周期,可以使用 timer_settime()。
1 | int timer_settime(timer_t timerid, int flags, const struct itimerspec *value, struct itimerspect *ovalue); |
如同 settimer(),it_value 用于指定当前的定时器到期时间。当定时器到期,it_value 的值会被更新成 it_interval 的值。如果 it_interval 的值为 0,则定时器不是一个时间间隔定时器,一旦 it_value 到期就会回到未启动状态。timespec 的结构提供了纳秒级分辨率:
1 | struct timespec{ |
如果 flags 的值为 TIMER_ABSTIME,则 value 所指定的时间值会被解读成绝对值 (此值的默认的解读方式为相对于当前的时间)。这个经修改的行为可避免取得当前时间、计算“该时间” 与“所期望的未来时间”的相对差额以及启动定时器期间造成竞争条件。
如果 ovalue 的值不是 NULL,则之前的定时器到期时间会被存入其所提供的 itimerspec。如果定时器之前处在未启动状态,则此结构的成员全都会被设定成 0。
销毁
1 | int timer_delete (timer_t timerid) |
一次成功的 timer_delete() 调用会销毁关联到 timerid 的定时器并且返回 0。执行失败时,此调用会返回 - 1 并将 errno 设定会 EINVAL,这个唯一的错误情况代表 timerid 不是一个有效的定时器。
sigaction
指定信号触发时的表现
1 | int sigaction(int signum,const struct sigaction *act ,struct sigaction *oldact); |
函数说明 sigaction()会依参数signum指定的信号编号来设置该信号的处理函数。参数signum可以指定SIGKILL和SIGSTOP以外的所有信号。
1 | struct sigaction { |
当注册信号捕捉函数,希望获取更多信号相关信息,不应使用sa_handler而应该使用sa_sigaction。但此时的sa_flags必须指定为SA_SIGINFO。 siginfo_t是一个成员十分丰富的结构体类型,可以携带各种与信号相关的数据。
1 | siginfo_t { |
sigval
传送的信号值
1 | sigval{ |
向指定进程发送指定信号的同时,携带数据。 但,如传地址,需注意,不同进程之间虚拟地址空间各自独立,将当前进程地址传递给另一进程没有实际意义。
sigqueue
加入信号队列… …
1 | sigqueue(pid_t pid, signal ,sigval) |
系统调用 sigqueue 发送信号时,sigqueue 的第三个参数就是 sigval 联合数据结构,当调用 sigqueue 时,该数据结构中的数据就将拷贝到信号处理函数的第二个参数中。这样,在发送信号同时,就可以让信号传递一些附加信息。信号可以传递信息对程序开发是非常有意义的。
Test
1 | struct sigaction act; |