一、介绍
setitimer()创建一个间隔式定时器(interval timer),会在未来某个点到期,并于此后每隔一段时间到期一次
getitimer()获取定时器了解当前状态、距离下次到期的剩余时间
alarm()为创建一次性实时定时器提供简单的一个接口
二、接口函数
#include <unistd.h>
unsigned int alarm(unsigned int seconds);
参数:
seconds: 表示定时器到期的秒数,到期时会产生SIGALRM信号并发送给进程,因为是实时和setitimer中的ITIMER_REAL一样
注意: alarm 和 settimer都是针对同一进程的共享实时定时器,也就是两者改变都会影响对方
调用alarm()会覆盖定时器前一个设置,调用alarm(0)会屏蔽现有定时器
alarm()返回值是定时器前一个设置距离到期的剩余次数,如未设置定时器则返回0
返回值:
alarm()返回的是剩余定时器时间
#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value,
struct itimerval *old_value);
参数:
which: 指定不同类型的定时器
ITIMER_REAL: 创建以真实时间倒计时的定时器,到期时会产生SIGALRM信号并发送给进程
ITIMER_VIRTUAL:创建以进程虚拟时间(用户态CPU时间)倒计时定时器,到期产生信号SIGVTALRM
ITIMER_PROF:创建一个运行时计时定时器,以进程时间(用户态+内核CPU时间的总和)倒计时,到期产生信号SIGPROF
new_value:
参数new_value下的it_value指定了距离定时器到期的延迟时间,it_interval则说明该定时器是否为周期性定时器,
如果it_interval两个字段均为0,那么定时器就属于在it_value所指定的时间间隔后到期的一次性定时器,
只要it_interval中的任一字段非0,那么每次定时器到期后,都会将定时器重置为指定间隔后再次到期。
注意:进程只能拥有which指定的三种中的一种,所以如果第二次调用setitimer修改类型要符合which中的类型,如果将
new_value->it_value下的两个字段都设置0,会屏蔽任何已有的定时器。
old_value:
若不为NULL,返回定时器前一设置。如果old_value->it_value两个字段都为0,那么该定时器之前处于屏蔽状态。
如果 old_valuee->it_interval两个字段为0,那么前一次是一次性定时器,如果不关心前一次设置那么设置NULL
返回值:
正确返回0,错误-1并设置errno
int getitimer(int which, struct itimerval *curr_value);
参数:
which: 参考setitimer
curr_value: 得到which指定类型的定时器信息
返回值:
正确返回0,错误-1并设置errno
SUSv4废止了UNIX API setitimer&getitimer,推荐使用POSIX定时器API
struct itimerval {
struct timeval it_interval; /* Interval for periodic timer */
struct timeval it_value; /* Time until next expiration */
};
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
三、实例 setitimer
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <utime.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <malloc.h>
#include <signal.h>
#include <setjmp.h>
#include <stdarg.h>
#ifdef TRUE
#undef TRUE
#endif
#define TRUE 1
#ifdef FALSE
#undef FALSE
#endif
#define FALSE 0
static volatile sig_atomic_t gotAlarm = 0;
void errExit(char * msg)
{
printf("%s\n",msg);
exit(EXIT_FAILURE);
}
void usageErr(const char *format, ...)
{
va_list argList;
fflush(stdout); /* Flush any pending stdout */
fprintf(stderr, "Usage: ");
va_start(argList, format);
vfprintf(stderr, format, argList);
va_end(argList);
fflush(stderr); /* In case stderr is not line-buffered */
exit(EXIT_FAILURE);
}
static void displayTimes(const char *msg, int includeTimer)
{
struct itimerval itv;
static struct timeval start;
struct timeval curr;
static int callNum = 0; /* Number of calls to this function */
if (callNum == 0) /* Initialize elapsed time meter */
if (gettimeofday(&start, NULL) == -1)
errExit("gettimeofday");
if (callNum % 20 == 0) /* Print header every 20 lines */
printf(" Elapsed Value Interval\n");
if (gettimeofday(&curr, NULL) == -1)
errExit("gettimeofday");
printf("%-7s %6.2f", msg, curr.tv_sec - start.tv_sec +(curr.tv_usec - start.tv_usec) / 1000000.0);
if (includeTimer) {
if (getitimer(ITIMER_REAL, &itv) == -1)
errExit("getitimer");
printf(" %6.2f %6.2f",itv.it_value.tv_sec + itv.it_value.tv_usec / 1000000.0,
itv.it_interval.tv_sec + itv.it_interval.tv_usec / 1000000.0);
}
printf("\n");
callNum++;
}
static void sigalrmHandler(int sig)
{
gotAlarm = 1;
}
int main(int argc, char *argv[])
{
struct itimerval itv;
clock_t prevClock;
int maxSigs; /* Number of signals to catch before exiting */
int sigCnt; /* Number of signals so far caught */
struct sigaction sa;
char *endptr;
if (argc > 1 && strcmp(argv[1], "--help") == 0)
usageErr("%s [secs [usecs [int-secs [int-usecs]]]]\n", argv[0]);
sigCnt = 0;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
sa.sa_handler = sigalrmHandler;
if (sigaction(SIGALRM, &sa, NULL) == -1)
errExit("sigaction");
/* Set timer from the command-line arguments */
itv.it_value.tv_sec = (argc > 1) ? strtol(argv[1], &endptr, 10):0;
itv.it_value.tv_usec = (argc > 2) ? strtol(argv[1], &endptr, 10):2;
itv.it_interval.tv_sec = (argc > 3) ? strtol(argv[1], &endptr, 10):0;
itv.it_interval.tv_usec = (argc > 4) ? strtol(argv[1], &endptr, 10):0;
/* Exit after 3 signals, or on first signal if interval is 0 */
maxSigs = (itv.it_interval.tv_sec == 0 && itv.it_interval.tv_usec == 0) ? 1 : 3;
displayTimes("START:", FALSE);
if (setitimer(ITIMER_REAL, &itv, NULL) == -1)
errExit("setitimer");
prevClock = clock();
sigCnt = 0;
for (;;) {
/* Inner loop consumes at least 0.5 seconds CPU time */
while (((clock() - prevClock) * 10 / CLOCKS_PER_SEC) < 5) {
if (gotAlarm) { /* Did we get a signal? */
gotAlarm = 0;
displayTimes("ALARM:", TRUE);
sigCnt++;
if (sigCnt >= maxSigs) {
printf("That's all folks\n");
exit(EXIT_SUCCESS);
}
}
}
prevClock = clock();
displayTimes("Main: ", TRUE);
}
}
yexiang@ubuntu:<_Sys>$ ./a.out 1 800000 1 0
Elapsed Value Interval
START: 0.00
Main: 0.50 0.50 1.00
ALARM: 1.00 1.00 1.00
Main: 1.00 1.00 1.00
Main: 1.50 0.50 1.00
ALARM: 2.00 1.00 1.00
Main: 2.00 1.00 1.00
Main: 2.50 0.50 1.00
ALARM: 3.00 1.00 1.00
That's all folks
四、实例alarm
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/time.h>
#include <time.h>
#include <utime.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/stat.h>
#include <string.h>
#include <dirent.h>
#include <limits.h>
#include <malloc.h>
#include <signal.h>
#include <setjmp.h>
#include <stdarg.h>
static void sig_alrm(int signo)
{
system("date");
return;
}
int main(void)
{
signal(SIGALRM,sig_alrm);
system("date");
alarm(20);
sleep(5);
printf("%d\n",alarm(5));
pause();
}
// alarm(5) 的时候会清除之前的定时器并且返回之前的剩余秒数,由于sleep了5秒,剩余15秒
// 并且5秒后触发信号,所以时间过去了10秒
yexiang@ubuntu:<_Sys>$ ./a.out
Thu Jan 16 18:59:32 PST 2020
15
Thu Jan 16 18:59:42 PST 2020
// 如果 alarm(5) 改为 alarm(0) 结果如下:
// 会一直等待,因为alarm(0) 取消掉了定时器不会触发信号
// pause又要等待信号执行才往下走,但等不到,所以一直等待
yexiang@ubuntu:<_Sys>$ ./a.out
Thu Jan 16 19:02:12 PST 2020
15
来源:CSDN
作者:HarkerYX
链接:https://blog.csdn.net/yexiangCSDN/article/details/103988960