介绍
最强大的定时器接口来自POSIX时钟系列,其创建、初始化以及删除一个定时器的行动被分为三个不同的函数:timer_create()、timer_settime()、timer_delete()
创建定时器
**int timer_create(clockid_t clock_id, struct sigevent evp, timer_t timerid)
clock_id说明定时器属于的时钟序号,*timerid装载的是被创建的定时器ID。函数创建一个定时器并指向timerid。
-
参数evp指定定时器到期产生的异步通知,evp为NULL则产生默认信号。若要产生非默认信号,则设置
evp->sigev_signo为期望新号码,evp->sigev_notify为通知行动。通常sigev_notify为SIGEV_SIGNAL,说明到期时产生一个新号。程序可以将其设置为SIGEV_NONE来防止定时器到时产生信号;
如果几个定时器产生了同一信号,处理程序可以用evp->sigev_value来区分。要实现这种功能,程序必须在为信号安装处理程序时,使用struct sigaction的成员sa_flags中的标志SA_SIGINFO;
clock_id取值CLOCK_REALTIME时为系统真实时间;
-
sigenv结构体
struct sigevent { int sigev_notify; // notifiction type int sigev_signo; // signal number union sigval sigev_value; // signal value void (*sigev_notify_function)(union sigval); // sigev_notify=SIGEV_THREAD pthread_attr_t *sigev_notifiction_attributes; } union sigval { int sigval_int; // integer value void *sigval_ptr; // pointer value }
sigev_notify = SIGEV_NONE时只提供通过timer_gettime和timer_getoverrun查询超时信息;
sigev_notify = SIGEV_SIGNAL当定时器超时内核将sigev_signo所指定的新号传送给进程。在信号处理程序中,si_val会被设置成sigev_value;
sigev_notify = SIGEV_THREAD当定时器到期内核会在此进程内以sigev_notifiction_attributes为线程参数创建一个线程,并且执行sigev_notify_function,传入sigev_value作为一个参数。
启动一个定时器
int timer_settime(timer_t timerid, int flags, const struct itimerspec * value, struct itimerspec ovalue)
timer_create()创建的定时器并未启动,将它关联到一个到期时间以及启动始终周期,可以使用timer_settime()*
-
itimespec结构体
struct itimespec { struct timespec it_interval; struct timespec it_value; }
it_value用于指定当前定时器到期时间。当定时器到期,则it_value会被更新为it_interval的值。若it_interval为0则定时器不是一个时间间隔定时器,一旦it_value到期就回到未启动的状态。
-
timespec结构体提供了纳秒级别分辨率:
struct timespec { timet_t tv_sec; long tv_nsec; }
若ovalue不是NULL,则之前的定时器到期时间会被存入ovalue。如果定时器之前处于未启动的状态,则此结构成员都为0。
获得一个活动定时器的剩余时间
*int timer_gettime(timer_t timerid, struct itimierspec value)
取得定时器的超限运行次数
int timer_getoverrun(timer_t timerid)
- 有可能一个定时器到期了,而这个定时器上一次产生的新号还处于挂起状态。这种情况下,其中的一个新号可能会丢失。这就是定时器超限。
- 通过调用timer_getoverrun()函数来确定定时器超限次数。超限只出现在同一定时器上,多个定时器产生信号会排队而不会丢失。
删除定时器
int timer_delete(timer_t timerid)
执行成功返回0,失败返回-1并将errno设为EINVAL,这个唯一的错误情况代表timerid不是一个有效定时器。
示例
int create_suicide_timeout(int sec_to_suicide)
{
timer_t timerid;
struct sigevent sev;
sigset_t mask;
struct itimerspec its;
struct sigaction sa;
sa.sa_sigaction = suicide_timeout_handler;
sigemptyset(&sa.sa_mask);
if (sigaction(SIGRTMIN, &sa, NULL) == -1) {
perror("sigaction");
return -1;
}
sigemptyset(&mask);
sigaddset(&mask, SIGRTMIN);
if (sigprocmask(SIG_SETMASK, &mask, NULL) == -1) {
perror("sigprocmask(SIG_SETMASK)");
return -1;
}
sev.sigev_notify = SIGEV_SIGNAL;
sev.sigev_signo = SIGRTMIN;
sev.sigev_value.sival_ptr = &timerid;
if (timer_create(CLOCK_REALTIME, &sev, &timerid) == -1) {
perror("timer_create");
return -1;
}
its.it_value.tv_sec = sec_to_suicide;
its.it_value.tv_nsec = 0;
its.it_interval.tv_sec = its.it_value.tv_sec;
its.it_interval.tv_nsec = its.it_value.tv_nsec;
if (timer_settime(timerid, 0, &its, NULL) == -1) {
perror("timer_settime");
return -1;
}
if (sigprocmask(SIG_UNBLOCK, &mask, NULL) == -1) {
perror("sigprocmask(SIG_UNBLOCK)");
return -1;
}
return 0;
}