如何使C计时器在Linux中的特定系统时间到期

我正在尝试创build一个取决于系统时钟定时器。 这意味着当系统时间改变时,它也会影响这个定时器的到期时间。 所以我想,创build一个基于CLOCK_REALTIME计时器应该做的伎俩。 但是,当这个定时器在60秒之后到期,并且当我使系统时钟提前32秒(使用date命令)时,定时器恰好在60秒之后过期。 它并没有在32秒前到期。

所以我计算了CLOCK_REALTIME和CLOCK_MONOTONIC时钟在2个定时器到期之间的时间。 它显示了CLOCK_REALTIME的92秒和CLOCK_MONOTONIC的60秒,这让我很惊讶,基于CLOCK_REALTIME的计时器没有查找系统时钟的变化。 任何人都可以解释这种行为?

#include <stdio.h> #include <signal.h> #include <time.h> #include <string.h> #include <sys/time.h> timer_t timerID; struct timespec rt1, rt2, mt1, mt2; void TimerCalback() { clock_gettime(CLOCK_REALTIME, &rt1); clock_gettime(CLOCK_MONOTONIC, &mt1); printf("%lu sec elapsed for CLOCK_REALTIME\n", rt1.tv_sec - rt2.tv_sec); printf("%lu sec elapsed for CLOCK_MONOTONIC\n", mt1.tv_sec - mt2.tv_sec); rt2 = rt1; mt2 = mt1; time_t rawtime; struct tm * timeinfo; time ( &rawtime ); timeinfo = localtime ( &rawtime ); printf("REALTIME Timer Expired at %s\n", asctime (timeinfo)); } void CreateTimer() { struct sigaction sa; sa.sa_flags = SA_SIGINFO; sa.sa_sigaction = TimerCalback; sigemptyset(&sa.sa_mask); sigaction(SIGRTMIN, &sa, NULL); struct sigevent te; memset(&te,0,sizeof(struct sigevent)); te.sigev_notify = SIGEV_SIGNAL; te.sigev_signo = SIGRTMIN; te.sigev_value.sival_ptr = &timerID; timer_create(CLOCK_REALTIME, &te, &timerID); struct itimerspec its; its.it_value.tv_sec = 1; its.it_value.tv_nsec = 0; its.it_interval.tv_sec = 60; its.it_interval.tv_nsec = 0; timer_settime(timerID, 0, &its, NULL); } void main() { CreateTimer(); while(1) { usleep(1); } } 

我得到了这个输出。 第一次到期后,我提前系统时钟。

 $ ./realtimeTimer 1407240463 sec elapsed for CLOCK_REALTIME 17747 sec elapsed for CLOCK_MONOTONIC REALTIME Timer Expired at Tue Aug 5 17:37:43 2014 92 sec elapsed for CLOCK_REALTIME 60 sec elapsed for CLOCK_MONOTONIC REALTIME Timer Expired at Tue Aug 5 17:39:15 2014 

后来在网上search,我偶然发现了这个手册

所有实现都支持由CLOCK_REALTIME标识的系统范围的实时时钟。 它的时间代表了Epoch以来的秒和纳秒。 当其时间改变时,相对时间间隔的定时器不受影响 ,但绝对时间点的定时器受到影响。

这可以成为这种行为的原因吗?
我在做什么错在这里?
有没有办法让计时器在特定的系统时间到期?

Solutions Collecting From Web of "如何使C计时器在Linux中的特定系统时间到期"

timer_settime的联机帮助timer_settime找到了相同的规则,并附加了一些说明:

默认情况下,在new_value->it_value指定的初始到期时间相对于调用时定时器时钟的当前时间进行解释。 这可以通过在标志中指定TIMER_ABSTIME来修改,在这种情况下,new_value-> it_value被解释为在定时器时钟上测量的绝对值; 也就是说,当时钟值达到new_value->it_value指定的值时,定时器将到期。 如果指定的绝对时间已经过去,则定时器立即到期,并且溢出计数(参见timer_getoverrun (2))将被正确设置。

如果CLOCK_REALTIME时钟的值被调整,而基于该时钟的绝对定时器被设防,则定时器的到期将被适当地调整。 对CLOCK_REALTIME时钟的调整对基于该时钟的相对定时器没有影响。

是的,你一直在设置一个相对定时器,这就是为什么它忽略了对系统时间的调整。

您可以尝试以下方法:

 struct timespec ts; clock_gettime(CLOCK_REALTIME, &ts); struct itimerspec its; its.it_value.tv_sec = ts.tv_sec + 1; its.it_value.tv_nsec = ts.tv_nsec; its.it_interval.tv_sec = 60; its.it_interval.tv_nsec = 0; timer_settime(timerID, TIMER_ABSTIME, &its, NULL); 

尝试这个:

 struct timeval tv; gettimeofday(&tv, NULL); struct itimerspec its; its.it_value.tv_sec = 1; its.it_value.tv_nsec = 0; its.it_interval.tv_sec = tv_sec + 60; its.it_interval.tv_nsec = tv_nsec; timer_settime(timerID, TIMER_ABSTIME, &its, NULL);