使用计时器每秒准确调用一个函数?

时间:2012-01-03 14:48:12

标签: c timer signals

我需要每秒调用一个函数,因为我想根据每秒存储数据,所以我不能错过第二个?什么是C的最佳方法?

下面是timer_create方法的骨架,这个可靠吗?

#include <stdio.h>
#include <time.h>
#include <signal.h>

timer_t gTimerid;

void start_timer(void)
{        
  struct itimerspec value;

  value.it_value.tv_sec = 1;
  value.it_value.tv_nsec = 0;  
  value.it_interval.tv_sec = 1;
  value.it_interval.tv_nsec = 0;

  timer_create (CLOCK_REALTIME, NULL, &gTimerid);    
  timer_settime (gTimerid, 0, &value, NULL);
}

void stop_timer(void)
{        
  struct itimerspec value;

  value.it_value.tv_sec = 0;
  value.it_value.tv_nsec = 0;    
  value.it_interval.tv_sec = 0;
  value.it_interval.tv_nsec = 0;

  timer_settime (gTimerid, 0, &value, NULL);        
}

void timer_callback(int sig)
{    
  printf(" Catched timer signal: %d ... !!\n", sig);     
}

int main(int ac, char **av)
{
    (void) signal(SIGALRM, timer_callback);
    start_timer();
    while(1);
}

5 个答案:

答案 0 :(得分:7)

在Linux和其他POSIX系统上,timer_create是您正在寻找的功能。将定时器设置为通过信号传送,它将非常可靠。不要使用旧的ualarmsetitimer api,这些apu已被弃用并且有各种丑陋的问题,除非您已经是实时unix内容的专家,否则您可能不想进入这些问题......

答案 1 :(得分:4)

您有两种方法可以每隔一秒调用一次函数:

  • 做一个“忙碌的等待”
  • 让您的进程/线程休眠一段时间

第一个选项肯定更准确,但CPU消耗更多,反应更少。只需使用whilefor循环即可完成。

这是 busy-wait 循环的一个小例子:

#include <time.h>

#define TIME_TO_WAIT 1 /* wait for one second */
...
clock_t last = clock();
while(1) {
    clock_t current = clock();
    if (current >= (last + TIME_TO_WAIT * CLOCKS_PER_SEC)) {
        yourSpecialFunction(); /* insert your function here */
        last = current;
    }
}

第二个选项可能不太准确(因为您的进程可能等待的时间少于或超过指定的时间),但它是多处理和调度方面的首选选项。您可以使用系统sleep() / usleep() / Sleep()(取决于您的系统)功能。或者,您可以使用信号。

答案 2 :(得分:3)

ualarm()可能是最简单的方法。正如其他人所提到的那样,不能保证完美的准确性,但分辨率可能已足够。

void each_sec(int x)
{
     printf("%d", (int)time(NULL));
}

int main()
{
    signal(SIGALRM, each_sec);
    ualarm(1000000, 1000000);
}

为了清晰起见,我使用了signal,但sigaction / sigprocmask更具便携性和功能。

答案 3 :(得分:2)

在Unix / Linux上,您可以使用计时器,这是一个例子:

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



int limit = 10;
/* signal process */
void timeout_info(int signo)
{
   if(limit == 0)
   {
       printf("Sorry, time limit reached.\n");
       exit(0);
   }
   printf("only %d senconds left.\n", limit--);
}

/* init sigaction */
void init_sigaction(void)
{
    struct sigaction act;

    act.sa_handler = timeout_info;
    act.sa_flags   = 0;
    sigemptyset(&act.sa_mask);
    sigaction(SIGPROF, &act, NULL);
} 

/* init */
void init_time(void)
{
    struct itimerval val;

    val.it_value.tv_sec = 1;
    val.it_value.tv_usec = 0;
    val.it_interval = val.it_value;
    setitimer(ITIMER_PROF, &val, NULL);
}


int main(void)
{
    char *str;
    char c;

    init_sigaction();
    init_time();
    printf("You have only 10 seconds for thinking.\n");

    while(1);
    exit(0);
}

将您自己的函数替换为timeout_info

答案 4 :(得分:0)

在Linux上,使用select()进行计时是很常见的。这样,您还可以收到有关文件描述符活动的通知。

您需要有一个struct timeval的间隔,并将其作为select的最后一个参数传递。