通常,实时应用程序使用间隔计时器来计划操作。间隔计时器可以分为以下两种类型:一次性类型或定期类型。
一次性计时器是已经过设置的计时器,设置为相对于当前时间或绝对时间的到期时间。计时器会到期一次然后解除设置。数据传输到存储器中或者使操作超时之后,即可使用此类型的计时器来清除缓冲区。
定期计时器设置有初始到期时间(绝对或相对)以及重复间隔。每次间隔计时器到期时,都会按照重复间隔重新装入此计时器。然后,重新设置此计时器。此计时器可帮助进行数据日志记录或伺服控制。调用间隔计时器接口时,会将小于计时器分辨率的时间值向上舍入为下一个硬件计时器间隔的倍数。此间隔通常为 10 ms。
SunOS 具有两组计时器接口。setitimer(2) 和 getitimer(2) 接口运行固定设置的计时器,此类计时器称为 BSD 计时器,使用 timeval 结构指定时间间隔。使用 timer_create(3RT) 创建的 POSIX 计时器用于运行 POSIX 时钟 CLOCK_REALTIME。POSIX 计时器操作以 timespec 结构表示。
getitimer(2) 和 setitimer(2) 函数分别用于检索和确定指定的 BSD 间隔计时器的值。可用于进程的三个 BSD 间隔计时器包括指定了 ITIMER_REAL 的实时计时器。如果 BSD 计时器已进行设置并允许到期,则系统会向设置此计时器的进程发送适当的信号。
timer_create(3RT) 例程最多可以创建 TIMER_MAX 个 POSIX 计时器。调用方可以指定计时器到期时应向进程发送的信号和关联值。timer_settime(3RT) 和 timer_gettime(3RT) 例程分别用于检索和确定指定的 POSIX 间隔计时器的值。所需的信号暂挂传送时,POSIX 计时器便会到期。此时会对计时器到期的次数进行计数,并且 timer_getoverrun(3RT) 将检索此计数。timer_delete(3RT) 用于解除分配 POSIX 计时器。
以下示例说明了如何使用 setitimer(2) 生成定期中断,以及如何控制计时器中断的到达。
#include <unistd.h> #include <signal.h> #include <sys/time.h> #define TIMERCNT 8 void timerhandler(); int timercnt; struct timeval alarmtimes[TIMERCNT]; main() { struct itimerval times; sigset_t sigset; int i, ret; struct sigaction act; siginfo_t si; /* block SIGALRM */ sigemptyset (&sigset); sigaddset (&sigset, SIGALRM); sigprocmask (SIG_BLOCK, &sigset, NULL); /* set up handler for SIGALRM */ act.sa_action = timerhandler; sigemptyset (&act.sa_mask); act.sa_flags = SA_SIGINFO; sigaction (SIGALRM, &act, NULL); /* * set up interval timer, starting in three seconds, * then every 1/3 second */ times.it_value.tv_sec = 3; times.it_value.tv_usec = 0; times.it_interval.tv_sec = 0; times.it_interval.tv_usec = 333333; ret = setitimer (ITIMER_REAL, ×, NULL); printf ("main:setitimer ret = %d\n", ret); /* now wait for the alarms */ sigemptyset (&sigset); timerhandler (0, si, NULL); while (timercnt < TIMERCNT) { ret = sigsuspend (&sigset); } printtimes(); } void timerhandler (sig, siginfo, context) int sig; siginfo_t *siginfo; void *context; { printf ("timerhandler:start\n"); gettimeofday (&alarmtimes[timercnt], NULL); timercnt++; printf ("timerhandler:timercnt = %d\n", timercnt); } printtimes () { int i; for (i = 0; i < TIMERCNT; i++) { printf("%ld.%0l6d\n", alarmtimes[i].tv_sec, alarmtimes[i].tv_usec); } }