间隔计时器未在指定时间间隔触发信号

Posted

技术标签:

【中文标题】间隔计时器未在指定时间间隔触发信号【英文标题】:Interval Timer not firing signal at specified time interval 【发布时间】:2018-06-09 01:02:21 【问题描述】:

我想每隔 2 秒调用一次 timer_handler 函数,而不管 timer_handler 函数的执行时间是我的代码

#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>

void timer_handler (int signum)

 static int count = 0;
 sleep(1);
 printf ("timer expired %d times %d signum \n", ++count, signum);


int main ()

 struct sigaction sa;
 struct itimerval timer;

 /* timer_handler as the signal handler for SIGVTALRM. */
 memset (&sa, 0, sizeof (sa));
 sa.sa_handler = &timer_handler;
 sigaction (SIGVTALRM, &sa, NULL);

 /* Configure the timer to expire after 2000 msec... */
 timer.it_value.tv_sec = 2;
 timer.it_value.tv_usec = 0;
 /* ... and every 2000 msec after that. */
 timer.it_interval.tv_sec = 2;
 timer.it_interval.tv_usec = 0;
 /* Start a virtual timer. It counts down whenever this process is
   executing. */
 setitimer (ITIMER_VIRTUAL, &timer, NULL);
 /* Do busy work. */
 while (1);

根据上面的代码,它应该每两秒打印一次timer expired 1 times 26 signum,但它每 3 秒打印一次,其中包括睡眠时间,所以我想每 2 秒调用一次该函数。 我不知道我在哪里做错了 如果任何其他图书馆能够做到这一点,请告诉我 谢谢

【问题讨论】:

在信号处理程序中使用不安全的函数有一长串,sleep()printf() 都在该列表中。 删除sleep()怎么样?你的最终目标是什么?我的意思是while (1) 很浪费。 @user3629249: As per POSIX sleep() 应该是异步信号安全的。 @alk,这里是sleep()的MAN页面的摘录┌──────────┬───────────── ┬────────────────────────────┐ │接口│属性│值│├──────────┼ ────────────────┼──────────────────────────────┤ │sleep() │ 线程安全 │ MT-Unsafe sig:SIGCHLD/linux │ └──────────┴──────────────┴────────── ────────────────────┘ 注意“Unsafe sig:SIGCHLD/linux”部分 @user3629249: 这个手册页你引用的是哪个 C 实现的文件? 【参考方案1】:

为什么不使用挂钟时间?

这样做

安装SIGALRM 的信号处理程序而不是SIGVTALRM 和 指定ITIMER_REAL 而不是ITIMER_VIRTUAL

无关但重要:信号处理程序只能调用异步信号安全函数。 printf() 不是其中之一。 For a list of the latter click here and scroll down.

【讨论】:

感谢您的回复,这对我很有帮助。现在我想要更多的功能。我想在调用 setitimer 后动态更改间隔时间,我该怎么做【参考方案2】:

信号处理程序中的调用:sleep(1) 为信号处理增加了额外的时间。这额外的一秒不是进程执行时间的一部分。

从信号处理程序中移除:

sleep(1);

关于:

setitimer (ITIMER_VIRTUAL, &timer, NULL);

因为您希望看到每 2 秒执行一次的信号处理程序,所以要使用的正确计时器是:ITIMER_REAL 而不是 ITIMER_VIRTUAL。这将导致测量“墙上的时钟”时间,而不是测量“进程运行”时间。

强烈建议让信号处理程序只设置一个标志。然后主函数中的“什么都不做”循环检查该标志,重置标志,然后调用 printf()将锁定互斥体,修改标志,然后解锁互斥体。

【讨论】:

以上是关于间隔计时器未在指定时间间隔触发信号的主要内容,如果未能解决你的问题,请参考以下文章

QML 定时器

JavaScript 计时器

qml 定时器以及几种简单动画

JavaScript的计时器对象

使用倒数计时器以特定间隔发出信号

JavaScript进阶