linux 定时器编程


    在编写应用程序的时候,经常需要用到定时器。根据使用情况,定时器的基本行为分为2种:Single-Shot Timer和Repeating Timer 。Single-Shot Timer 从注册到终止只执行一次。Repeating Timer每次终止后自动执行。

    linux 在定时编程有以下几种接口:一是 setitimer ,二是Posix标准的 timer_create,三是timerfd_create。
    linux内核2.4版本,不支持POSIX标准的timer_create接口。setitimer是一个间隔定时器,也就是定时到期后,可以自动启动自己。原型如下:

struct itimerval { 
     struct timeval it_interval; /* next value */ 
     struct timeval it_value;     /* current value */ 
 }; 

 struct timeval { 
    long tv_sec;                /* seconds */ 
    long tv_usec;               /* microseconds */ 
 };

 int setitimer(int which, const struct itimerval *new_value,struct itimerval *old_value);
 int getitimer(int which, struct itimerval *curr_value);

该函数有一下三种工作模式:

TIMER_REAL 以实时时间 (real time) 递减,在到期之后发送 SIGALRM 信号

ITIMER_VIRTUAL 仅进程在用户空间执行时递减,在到期之后发送 SIGVTALRM 信号

ITIMER_PROF 进程在用户空间执行以及内核为该进程服务时 ( 如完成一个系统调用 ) 都会递减ITIMER_VIRTUAL 共用时可度量该应用在内核空间和用户空间的时间消耗情况,在到期之后发送 SIGPROF 信号

   工作方式为:setitimer以new_value的值设置并启动定时器,如果old_value的值为非空,则返回定时器的which 类型时间间隔的前一个值。settimer从it_value开始递减到0,然后产生一个信号,并以it_interval的值设置定时器。如果it_interval的值为0,定时器停止。

   setitimer不支持在进程中调用多次以使用多个定时器。settimer要在进程中支持多次个定时器,可以用链表和信号处理方式实现。基本思想是settimer定时为基本的单位如10ms, 每个定时器为链表的一个节点,每次超时,每个定时器的定时时间递,并检查是否到时,是的话就执行注册的定时处理函数。

   与seitimer相比,linux2.6版本支持的POSIX标准timer_create函数可以在一个进程中创建多个定时器。主要接口如下:

 #include <time.h> 

union sigval { 
 int sival_int; 
 void *sival_ptr; 
 }; 

 struct sigevent { 
    int sigev_notify;               /* Notification method */ 
    int sigev_signo;                /* Timer expiration signal */ 
    union sigval sigev_value;       /* Value accompanying signal or passed to thread function */ 
    void (*sigev_notify_function) (union sigval); /* Function used for thread notifications (SIGEV_THREAD) */ 
    void *sigev_notify_attributes;  /* Attributes for notification thread (SIGEV_THREAD) */ 
   pid_t sigev_notify_thread_id;    /* ID of thread to signal (SIGEV_THREAD_ID) */ 
 };

struct itimerspec {
    struct timespec it_interval;    /* timer period */
    struct timespec it_value;    /* timer expiration */
};

<span style="font-size:12px;">int timer_create(clockid_t clockid, struct sigevent *evp, timer_t *timerid);
int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value,
                  struct itimerspec * old_value); 
int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
int timer_getoverrun(timer_t timerid); int timer_delete(timer_t timerid);</span> 


    clockid定义的定时器类型,分为以下几种:

CLOCK_REALTIME :墙上时钟,如果墙上时间被修改,定时时间将变化。如在8点10分设置定时1分钟,则8点11分定时到期,在定期超时之前如果墙上时间被修改为7点0分,则要等待71分钟才超时。

CLOCK_MONOTONIC:结束与开始的相对时间计算超时。

CLOCK_PROCESS_CPUTIME_ID:以进程占用的CPU时间计算超时

CLOCK_THREAD_CPUTIME_ID:以线程占用的CPU时间计算超时

     工作方式为:timer_create创建定时器,timer_settime启动定时器。定时器超时后,以it_interval的值设置定时器,根据创建时设置的超时通知方式处理超时。如果it_interval的值为0,定时结束,否则开始下一次定时。定时器的启动和停止都是通过timer_settime实现。

sigev_notify的超时通知方式有:

SIGEV_NONE: 超时不以异步的方式通知。可以调用timer_gettime的方式获取定时器的状态,但是需要注意的是用这种方式检查定时器的超时,并不准确,在有可能在调用timer_gettime之前刚好超时已经过了,如果对定时精度不高如100ms级别可以使用。

SIGEV_SIGNAL:超时以信号的方式通知。每次超时发送一个sigev_signo指定的信号。超时时可以将sigev_value.sival_int设置为timerid的值,以此来区分多个定时器发送相同信号的情况。(如何实现?)

SIGEV_THREAD:超时时创建一个线程的方式通知。线程的属性通过sigev_notify_attributes设置。

         POSIX的timer_create只适合在进程中使用,不适合在多线程下使用。为了支持在多线程下使用多个定时器,linux提供了基于文件描述符的定时器接口:

#include <sys/timerfd.h> 

int timerfd_create(int clockid, int flags); 
int timerfd_settime(int fd, int flags,const struct itimerspec *new_value,
                    struct itimerspec *old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);
      这种接口支持select函数和poll函数,并且支持fork和exec多进程语义。



参考资料:

Linux 下定时器的实现方式分析---赵军

http://www.ibm.com/developerworks/cn/linux/l-cn-timers/#5.%E5%9F%BA%E4%BA%8E%E6%97%B6%E9%97%B4%E8%BD%AE%28Timing-Wheel%29%E6%96%B9%E5%BC%8F%E5%AE%9E%E7%8E%B0%E7%9A%84%E5%AE%9A%E6%97%B6%E5%99%A8%7Coutline






  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值