当前位置: 首页 > 工具软件 > itimer > 使用案例 >

间隔定时器itimer

龙玺
2023-12-01

间隔定时器的接口如下:

#include <sys/time.h>

int getitimer(int which, struct itimerval *curr_value);
int setitimer(int which, const struct itimerval *new_value,
        struct itimerval *old_value);
结构定义:
struct itimerval {
    struct timeval it_interval; /* next value :间隔时间*/
    struct timeval it_value;    /* current value:到期时间*/
};
struct timeval {
    time_t      tv_sec;         /* seconds */
    suseconds_t tv_usec;        /* microseconds */
};

可以通过调用上面两个API接口来设置和获取间隔定时器信息。系统为每个进程提供了3种itimer,每种定时器在不同时间域递减,当定时器超时,就会向进程发送一个信号,并且重置定时器。3种定时器的类型,如下表所示:

取值含义信号发送
ITIMER_REAL定时真实时间,与alarm类型相同。SIGALRM
ITIMER_VIRT定时进程在用户态下的实际执行时间。SIGVTALRM
ITIMER_PROF定时进程在用户态和核心态下的实际执行时间。SIGPROF

表1 参数which与定时器类型

在Linux 2.6.16 之前,itimer的实现是基于内核定时器timer wheel封装成的定时器接口。内核封装的定时器接口是提供给其他内核模块使用,也是其他定时器的基础。itimer通过内核定时器的封装,生成提供给用户层使用的接口setitimer和getitimer。内核定时器timer wheel提供的内核态调用接口为:可参考

https://github.com/torvalds/linux/blob/master/kernel/time/timer.c

add_timer() 
del_timer() 
init_timer()

在Linux 2.6.16 以来,itimer不再采用基于timer wheel的内核定时器进行实现。而是换成了高精度的内核定时器hrtimer进行实现。具体实现可参考:
https://github.com/torvalds/linux/blob/master/kernel/time/itimer.c

如果定时器超时时,进程是处于运行状态,那么超时的信号会被立刻传送给该进程,否则信号会被延迟传送,延迟时间要根据系统的负载情况。所以这里有一个BUG:当系统负载很重的情况下,对于ITIMER_REAL定时器有可能在上一次超时信号传递完成前再次超时,这样就会导致第二次超时的信号丢失

每个进程中同一种定时器只能使用一次。
该系统调用在POSIX.1-2001中定义了,但在POSIX.1-2008中已被废弃。所以建议使用POSIX定时器API(timer_gettime, timer_settime)代替。

函数alarm本质上设置的是低精确、非重载的ITIMER_REAL类定时器,它只能精确到秒,并且每次设置只能产生一次定时。函数setitimer 设置的定时器则不同,它们不但可以计时到微妙(理论上),还能自动循环定时。在一个Unix进程中,不能同时使用alarm和ITIMER_REAL类定时器。
下面是测试代码:

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

#include <iostream>

void sig_handler(int signo)
{
    std::cout<<"recieve sigal: "<<signo<<std::endl;
}

int main()
{
    signal(SIGALRM, sig_handler);

    struct itimerval timer_set;

    //启动时间(5s后启动)
    timer_set.it_value.tv_sec = 5;
    timer_set.it_value.tv_usec = 0;

    //间隔定时器间隔:2s
    timer_set.it_interval.tv_sec = 2;
    timer_set.it_interval.tv_usec = 0;

    if(setitimer(ITIMER_REAL, &timer_set, NULL) < 0)
    {
        std::cout<<"start timer failed..."<<std::endl;
        return 0;
    }

    int temp;
    std::cin>>temp;

    return 0;
}

 

 类似资料: