POSIX Timer
SYNOPSIS
#include <signal.h> /* only timer_create need this header */ #include <time.h> int timer_create(clockid_t clockid, struct sigevent *restrict evp, timer_t *restrict timerid); int timer_delete(timer_t timerid); int timer_gettime(timer_t timerid, struct itimerspec *value); int timer_settime(timer_t timerid, int flags, const struct itimerspec *restrict new_value, struct itimerspec *restrict old_value); int timer_getoverrun(timer_t timerid);
Date Structure
struct sigevent 的详细定义请参见:http://www.cnblogs.com/LubinLew/p/POSIX-DataStructure.html#sigevent
struct itimerspec 的详细定义请参见:http://www.cnblogs.com/LubinLew/p/POSIX-DataStructure.html#itimerspec
clockid_t 的详细定义请参见:http://www.cnblogs.com/LubinLew/p/POSIX-DataStructure.html#clockid_t
FUNCTION DETAIL
1) timer_create
DESCRIPTION
函数 timer_create 会创建一个timer(每进程), 返回的timer id 在调用进程中是唯一的, 创建后的timer处于停止(disarmed)状态.
PARAMETERS
① clockid [IN]
使用的时钟类型, 取值范围为以下4种
② evp [IN]
timer到期时的通知方法,详见:http://www.cnblogs.com/LubinLew/p/POSIX-DataStructure.html#sigevent
该类型结构体使用之前一定要初始化(memset等), 否则可能会出现timer到期无动作的异常情况.
③ timerid [OUT]
创建的timer的id 通过这个指针返回.
RETURN VALUE
timer创建成功该函数返回0,并且更新timerid;否则函数返回-1,并且设置errno标识错误种类,具体如下.
[EAGAIN]
系统没有足够的信号队列资源来响应创建一个新timer的请求,或者调用进程创建的timer总数已达到最大值,无法创建新的timer.
[EINVAL]
第一个参数无效(The specified clock ID is not defined.)
[ENOTSUP]
该平台实现不支持clock ID 为CLOCK_PROCESS_CPUTIME_ID 和 CLOCK_THREAD_CPUTIME_ID.
2) timer_delete
DESCRIPTION
通过timder id删除指定的 timer.
如果调用这个函数时,timer处于激活(armed)状态, 删除前会先将这个timer状态变更为未激活(disarmed)状态.
挂起等待timer(删除的)产生信号的行为是未定义的.
PARAMETERS
① timerid [IN]
指定的timer
RETURN VALUE
timer删除成功该函数返回0;否则函数返回-1,并且设置errno标识错误种类,具体如下.
[EINVAL]
参数无效(The timer ID specified by timerid is not a valid timer ID.)
3) timer_settime
DESCRIPTION
启动(armed) / 停止(disarmed) / 重置 timer.
PARAMETERS
① timerid [IN]
指定的timer
② flags [IN]
flags 取值只有2个 : 0 和 TIMER_ABSTIME.
⑴ 当 flags 为 0 时, new_value->it_value 表示希望timer首次到期时的时间与启动timer的时间间隔(例如,希望timer 在 2秒后到期).
⑵ 当flags为 TIMER_ABSTIME 时, new_value->it_value 表示希望timer首次到期的绝对时间(例如希望timer 在 01:23:45 到期);
如果new_value->it_value 设定的绝对时间 早于 当前的绝对时间, 那么timer会立即到期.
如果时钟 CLOCK_REALTIME 被调整了,那么timer的首次过期时间也会适当调整.
③ new_value [IN]
new_value 有2个子域: it_value 和 it_interval.
⑴ it_value : 用于设置首次timer到期的时间, 也是 启动/停止 timer的控制域;
⑵ it_interval : 用于设置timer循环的时间间隔, 如果其值不为0(秒和纳秒至少有一个不为0),每次timer到期时,timer会使用new_value->it_interval的值重新加载timer;
如果其值为0, timer只会在it_value指定的时间到期一次,之后不会重新加载timer.
⑴ 启动timer
前提:timer处于停止(disarmed)状态,否则就是重置timer
设置:new_value->it_value的值是非0值(秒和纳秒都不等于0或者其中一个不等于0)
结果:timer变为启动(armed)状态.
⑵ 停止timer
设置:new_value->it_value的的值为0(秒和纳秒都为0)
结果:timer变为停止(disarmed)状态.
⑶ 重置timer
前提:timer处于已启动(armed)状态,否则就是启动timer
设置:new_value->it_value的的值不为0(秒和纳秒至少有一个不为0)
结果:timer仍为(armed)状态.之前的参数(即new_value(it_value 和 it_interval))设置会被覆盖.
④ old_value [OUT]
取得上一次的设置的new_value.
RETURN VALUE
操作成功该函数返回0;否则函数返回-1,并且设置errno标识错误种类,具体如下:
[EINVAL]
⑴ [shall fail] new_value.it_value is negative; or new_value->it_value.tv_nsec is negative or greater than 999,999,999.
⑵ [may fail] new_value->it_interval不为0,并且timer的到期通知方式为创建新线程(sigev_sigev_notify = SIGEV_THREAD)并且在线程属性中设置了固定的栈地址.
4) timer_gettime
DESCRIPTION
获取指定timer的信息(离timer到期的剩余时间 和 timer的循环时间间隔).
PARAMETERS
① timerid [IN]
指定的timer
② value[OUT]
value->it_value : 离timer到期的剩余时间
value->it_interval : timer的循环时间间隔
RETURN VALUE
操作成功该函数返回0;否则函数返回-1,并且设置errno标识错误种类,具体如下:
[EINVAL]
timerid is invalid.
5) timer_getoverrun
DESCRIPTION
当一个timer到期并且上一次到期时产生的信号还处于挂起状态时,不会产生新的信号(即丢弃一个信号),这就是定时器超限(overrun), 丢弃的信号数量就是 overrun count。
对于一个给定的timer, 在任何时间点只能有一个信号在进程中排队, 这是POSIX.1-2001中指定的, 因为不这样做,排队信号的数量很容易达到系统的上限.
因为系统调度延迟或者信号被暂时阻塞都会造成信号产生到信号被发送( (e.g., caught by a signal handler))或者接收((e.g., using sigwaitinfo(2)))之间有一个延迟的时间段,在这个时间段中可能会有多次的timer到期.
程序可以通过调用timer_getoverrun来确定一个指定的定时器出现这种超限的次数, 从而精确能精确的计算出在给定时间内timer到期了多少次。
定时器超限只能发生在同一个定时器产生的信号上。多个定时器,甚至是那些使用相同的时钟和信号的定时器,所产生的信号都会排队而不会丢失。
如果超限运行的次数等于或大于 {DELAYTIMER_MAX},则此调用会返回 {DELAYTIMER_MAX}.
PARAMETERS
① timerid [IN]
指定的timer
RETURN VALUE
执行成功,返回 "overrun count" (>=0), 失败返回-1,并且设置errno标识错误种类,具体如下:
[EINVAL]
timerid is invalid.
EXAMPLE
例子1:一次性timer,使用相对时间
#include <signal.h> /* union sigval / struct sigevent */ #include <stdio.h> /* printf */ #include <string.h> /* memset */ #include <unistd.h> /* sleep */ #include <time.h> #define printf_with_time(format, ...) \ { \ struct timespec spec; \ clock_gettime(CLOCK_MONOTONIC, &spec); \ printf("[%lu:%lu]"format"\n", spec.tv_sec, spec.tv_nsec, ##__VA_ARGS__);\ } timer_t id; void timer_notify_cb(union sigval val) { printf_with_time("timer expiration"); printf_with_time("delete timer"); timer_delete(id); } int main(void) { /* Variable Definition */ struct timespec spec; struct sigevent ent; struct itimerspec value; struct itimerspec get_val; /* Init */ memset(&ent, 0x00, sizeof(struct sigevent)); memset(&get_val, 0x00, sizeof(struct itimerspec)); /* create a timer */ ent.sigev_notify = SIGEV_THREAD; ent.sigev_notify_function = timer_notify_cb; printf_with_time("create timer"); timer_create(CLOCK_MONOTONIC, &ent, &id); /* start a timer */ value.it_value.tv_sec = 2; value.it_value.tv_nsec = 0; value.it_interval.tv_sec = 0; value.it_interval.tv_nsec = 0; printf_with_time("start timer"); timer_settime(id, 0, &value, NULL); sleep(3); return 0; }
例子2:循环timer,使用绝对时间
#include <signal.h> /* union sigval / struct sigevent */ #include <stdio.h> /* printf */ #include <string.h> /* memset */ #include <unistd.h> /* sleep */ #include <time.h> #define printf_with_time(format, ...) \ { \ struct timespec spec; \ clock_gettime(CLOCK_MONOTONIC, &spec); \ printf("[%lu:%lu]"format"\n", spec.tv_sec, spec.tv_nsec, ##__VA_ARGS__);\ } void timer_notify_cb(union sigval val) { printf_with_time("timer expiration"); } int main(void) { /* Variable Definition */ timer_t id; struct timespec spec; struct sigevent ent; struct itimerspec value; struct itimerspec get_val; /* Init */ memset(&ent, 0x00, sizeof(struct sigevent)); memset(&get_val, 0x00, sizeof(struct itimerspec)); /* create a timer */ ent.sigev_notify = SIGEV_THREAD; ent.sigev_notify_function = timer_notify_cb; printf_with_time("create timer"); timer_create(CLOCK_REALTIME, &ent, &id); /* CLOCK_REALTIME */ /* start a timer */ clock_gettime(CLOCK_REALTIME, &spec); /* CLOCK_REALTIME */ value.it_value.tv_sec = spec.tv_sec + 2; value.it_value.tv_nsec = spec.tv_nsec + 0; value.it_interval.tv_sec = 1; /* per second */ value.it_interval.tv_nsec = 0; printf_with_time("start timer"); timer_settime(id, TIMER_ABSTIME, &value, NULL); /* TIMER_ABSTIME */ sleep(10); printf_with_time("delete timer"); timer_delete(id); return 0; }
例子3:timer_gettime
#include <signal.h> /* union sigval / struct sigevent */ #include <stdio.h> /* printf */ #include <string.h> /* memset */ #include <unistd.h> /* sleep */ #include <time.h> #define printf_with_time(format, ...) \ { \ struct timespec spec; \ clock_gettime(CLOCK_MONOTONIC, &spec); \ printf("[%lu:%lu]"format"\n", spec.tv_sec, spec.tv_nsec, ##__VA_ARGS__);\ } timer_t id; void timer_notify_cb(union sigval val) { printf_with_time("timer expiration"); } int main(void) { /* Variable Definition */ struct timespec spec; struct sigevent ent; struct itimerspec value; struct itimerspec get_val; /* Init */ memset(&ent, 0x00, sizeof(struct sigevent)); memset(&get_val, 0x00, sizeof(struct itimerspec)); /* create a timer */ ent.sigev_notify = SIGEV_THREAD; ent.sigev_notify_function = timer_notify_cb; printf_with_time("create timer"); timer_create(CLOCK_MONOTONIC, &ent, &id); /* start a timer */ value.it_value.tv_sec = 5; value.it_value.tv_nsec = 0; value.it_interval.tv_sec = 2; value.it_interval.tv_nsec = 123456789; printf_with_time("start timer"); timer_settime(id, 0, &value, NULL); sleep(2); timer_gettime(id, &get_val); printf_with_time("timer will expiration after %lu.%lus", get_val.it_value.tv_sec, get_val.it_value.tv_nsec); printf_with_time("timer repeat period = %lu.%lus", get_val.it_interval.tv_sec, get_val.it_interval.tv_nsec); sleep(10); printf_with_time("delete timer"); timer_delete(id); return 0; }
例子4:timer_getoverrun
#include <signal.h> /* union sigval / struct sigevent */ #include <stdio.h> /* printf */ #include <string.h> /* memset */ #include <unistd.h> /* sleep */ #include <time.h> #define printf_with_time(format, ...) \ { \ struct timespec spec; \ clock_gettime(CLOCK_MONOTONIC, &spec); \ printf("[%lu:%lu]"format"\n", spec.tv_sec, spec.tv_nsec, ##__VA_ARGS__);\ } timer_t id; void timer_notify_cb(union sigval val) { printf_with_time("timer expiration"); } int main(void) { /* Variable Definition */ struct timespec spec; struct sigevent ent; struct itimerspec value; struct itimerspec get_val; /* Init */ memset(&ent, 0x00, sizeof(struct sigevent)); memset(&get_val, 0x00, sizeof(struct itimerspec)); /* create a timer */ ent.sigev_notify = SIGEV_THREAD; ent.sigev_notify_function = timer_notify_cb; printf_with_time("create timer"); timer_create(CLOCK_MONOTONIC, &ent, &id); /* start a timer */ value.it_value.tv_sec = 1; value.it_value.tv_nsec = 0; value.it_interval.tv_sec = 0; value.it_interval.tv_nsec = 5000; printf_with_time("start timer"); timer_settime(id, 0, &value, NULL); sleep(2); printf_with_time("overrun count = %d", timer_getoverrun(id)); printf_with_time("delete timer"); timer_delete(id); return 0; }
例子5:发送信号方式通知
#include <signal.h> /* union sigval / struct sigevent */ #include <stdio.h> /* printf */ #include <string.h> /* memset */ #include <unistd.h> /* sleep */ #include <stdlib.h> /* exit */ #include <time.h> #define printf_with_time(format, ...) \ { \ struct timespec spec; \ clock_gettime(CLOCK_MONOTONIC, &spec); \ printf("[%lu:%lu]"format"\n", spec.tv_sec, spec.tv_nsec, ##__VA_ARGS__);\ } timer_t id; void sighandler_cb(int val) { if (SIGUSR2 == val) { printf_with_time("sighandler"); } else { printf_with_time("delete timer"); timer_delete(id); exit(EXIT_SUCCESS); } } int main(void) { /* Variable Definition */ struct sigevent ent; struct itimerspec value; /* Init */ memset(&ent, 0x00, sizeof(struct sigevent)); /* register singnal handler */ signal(SIGUSR2, sighandler_cb); /* for timer */ signal(SIGINT, sighandler_cb); /* Ctrl + C */ /* create a timer */ ent.sigev_notify = SIGEV_SIGNAL; ent.sigev_signo = SIGUSR2; printf_with_time("create timer"); timer_create(CLOCK_MONOTONIC, &ent, &id); /* start a timer */ value.it_value.tv_sec = 2; value.it_value.tv_nsec = 0; value.it_interval.tv_sec = 1; value.it_interval.tv_nsec = 0; printf_with_time("start timer"); timer_settime(id, 0, &value, NULL); while(1); /* Ctrl + C */ return 0; }