linux 定时器总结

Linux定时器 setitimer 设置“闹钟”
2010-04-12 15:19
下面这个例子显示了设置闹钟的方法。

源代码是:
#include <signal.h>
#include <unistd.h>
#include <stdio.h>
#include <sys/time.h>
/************关于本文档********************************************
*filename: setitimer.c
*purpose: 显示了设置闹钟的方法
*
*********************************************************************/
void sigroutine(int signo) {
        switch (signo) {
                case SIGALRM:
                        printf("Catch a signal -- SIGALRM\n");
                        break;
                case SIGVTALRM:
                        printf("Catch a signal -- SIGVTALRM\n");
                        break;
        }
}

int main(int argc, char ** argv) {
        struct itimerval value,ovalue,value2;

        printf("process id is %d\n",getpid());
        signal(SIGALRM, sigroutine);
        signal(SIGVTALRM, sigroutine);

        value.it_value.tv_sec = 1;
        value.it_value.tv_usec = 0;
        value.it_interval.tv_sec = 1;
        value.it_interval.tv_usec = 0;
        setitimer(ITIMER_REAL, &value, &ovalue); /* 这将每隔1秒钟后产生 SIGALRM 信号 */

        value2.it_value.tv_sec = 0;
        value2.it_value.tv_usec = 500000;
        value2.it_interval.tv_sec = 0;
        value2.it_interval.tv_usec = 500000;
        setitimer(ITIMER_VIRTUAL, &value2, &ovalue); /* 对于在运行的程序,这将每隔0.5秒钟后产生 SIGVTALRM 信号。在sleep时间内是不产生闹钟的 */

        for (;;) ;
}
编译此程序:
gcc -Wall setitimer.c
运行程序:
./a.out

man setitimer 得到如下内容:
SYNOPSIS
       #include <sys/time.h>

       int getitimer(int which, struct itimerval *value);
       int setitimer(int which, const struct itimerval *value,
                     struct itimerval *ovalue);

DESCRIPTION
       The system provides each process with three interval timers, each decrementing in a distinct time domain. When any timer expires, a
       signal is sent to the process, and the timer (potentially) restarts.

       ITIMER_REAL    decrements in real time, and delivers SIGALRM upon expiration.

       ITIMER_VIRTUAL decrements only when the process is executing, and delivers SIGVTALRM upo expiration.

       ITIMER_PROF    decrements both when the process executes and when the system is executing on behalf of the process.   Coupled with
                      ITIMER_VIRTUAL, this timer is usually used to profile the time spent by the application in user and kernel space.
                      SIGPROF is delivered upon expiration.

       Timer values are defined by the following structures:

            struct itimerval {
                struct timeval it_interval; /* next value */
                struct timeval it_value;    /* current value */
            };
            struct timeval {
                long tv_sec;                /* seconds */
                long tv_usec;               /* microseconds */
            };

       The function getitimer() fills the structure indicated by value with the current setting for the timer indicated by which (one of
       ITIMER_REAL, ITIMER_VIRTUAL, or ITIMER_PROF). The element it_value is set to the amount of time remaining on the timer, or zero if
       the timer is disabled. Similarly, it_interval is set to the reset value. The function setitimer() sets the indicated timer to the
       value in value. If ovalue is non-zero, the old value of the timer is stored there.

显然,我们首先设置it_value时间,这个时间就会自动减少,当减少到0时就会产生ITIMER信号,然后it_value将设置为it_interval的值重复上述闹钟计时过程。因此可以每隔一定时间“闹钟”一次。
而闹钟信号分为三种,ITIMER_REAL、ITIMER_VIRTUAL、ITIMER_PROF分别代表了当系统运行时产生闹钟、当进程在运行时产生闹钟、两种情况下都会产生。通常情况下,只要我们启动了程序闹钟,ITIMER_REAL计时就一定会持续进行;如果是ITIMER_VIRTUAL则只有在程序在运行时计时,如果你程序里有sleep之类的调用,则在sleep的时候是不会产生SIGVTALRM闹钟的。
比如下面这个代码将只会产生SIGALRM闹钟:

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

void sigroutine(int signo) {
        switch (signo) {
                case SIGALRM:
                        printf("Catch a signal -- SIGALRM\n");
                        break;
                case SIGVTALRM:
                        printf("Catch a signal -- SIGVTALRM\n");
                        break;
        }
}

int main(int argc, char ** argv) {
        struct itimerval value,ovalue,value2;
        int i = 0;

        printf("process id is %d\n",getpid());
        signal(SIGALRM, sigroutine);
        signal(SIGVTALRM, sigroutine);

        value.it_value.tv_sec = 1;
        value.it_value.tv_usec = 0;
        value.it_interval.tv_sec = 1;
        value.it_interval.tv_usec = 0;
        setitimer(ITIMER_REAL, &value, &ovalue);

        value2.it_value.tv_sec = 0;
        value2.it_value.tv_usec = 500000;
        value2.it_interval.tv_sec = 0;
        value2.it_interval.tv_usec = 500000;
        setitimer(ITIMER_VIRTUAL, &value2, &ovalue);

        for (i = 0; i < 50; i++) {
                usleep(100000);
        }
        return 0;
}



Linux 定时器设置(一)
2010-04-12 17:07
定时器设置
函数alarm设置的定时器只能精确到秒,而以下函数理论上可以精确到微妙:
#include <sys/select.h>
#include <sys/time.h>
int getitimer(int which, struct itimerval *value);
int setitimer(int which, const struct itimerval *value, struct itimerval *ovalue);
函数setitimer可以提供三种定时器,它们相互独立,任意一个定时完成都将发送定时信号到进程,并且自动重新计时。参数which确定了定时器的类型,如表10-6所示:
表10-6 参数which与定时器类型
取值
含义
信号发送
ITIMER_REAL
定时真实时间,与alarm类型相同。
SIGALRM
ITIMER_VIRT
定时进程在用户态下的实际执行时间。
SIGVTALRM
ITIMER_PROF
定时进程在用户态和核心态下的实际执行时间。
SIGPROF
这三种定时器定时完成时给进程发送的信号各不相同,其中ITIMER_REAL类定时器发送SIGALRM信号,ITIMER_VIRT类定时器发送SIGVTALRM信号,ITIMER_REAL类定时器发送SIGPROF信号。
函数alarm本质上设置的是低精确、非重载的ITIMER_REAL类定时器,它只能精确到秒,并且每次设置只能产生一次定时。函数setitimer设置的定时器则不同,它们不但可以计时到微妙(理论上),还能自动循环定时。在一个Unix进程中,不能同时使用alarm和ITIMER_REAL类定时器。
结构itimerval描述了定时器的组成:
struct itimerval
{
    struct tim. it_interval;    /* 下次定时取值 */
    struct tim. it_value;       /* 本次定时设置值 */
}
    结构tim.描述了一个精确到微妙的时间:
struct tim.
{
    long    tv_sec;                 /* 秒(1000000微秒) */
    long    tv_usec;                 /* 微妙 */
}
函数setitimer设置一个定时器,参数value指向一个itimerval结构,该结构决定了设置的定时器信息,结构成员it_value指定首次定时的时间,结构成员it_interval指定下次定时的时间。定时器工作时,先将it_value的时间值减到0,发送一个信号,再将it_value赋值为it_interval的值,重新开始定时,如此反复。如果it_value值被设置为0,则定时器停止定时;如果it_value值不为0但it_interval值为0,则定时器在一次定时后终止。
函数setitimer调用成功时返回0,否则返回-1,参数ovalue如果不为空,返回上次的定时器状态。
函数getitimer获取当前的定时器状态,整型参数which指定了读取的定时器类型,参数value返回定时器状态。函数调用成功返回0,否则返回-1。

Linux 定时器设置(二)
2010-04-12 17:13
例1. 设置一个定时器,每2.5秒产生一个SIGALRM信号。
答:将itimerval结构的成员it_interval和成员it_value均赋值为2.5秒即可:
struct itimerval value;
value.it_value.tv_sec=2;
value.it_value.tv_usec=500000;
value.it_interval.tv_sec=2;
value.it_interval.tv_usec=500000;
setitimer(ITIMER_REAL, &value, NULL);
函数setitimer设置的定时器可以重复定时,无需多次调用。
例2. 设置一个定时器,进程在用户态下执行1秒钟后发出首次信号,以后进程每在用户态下执行3秒钟,发送一个信号。
答:将itimerval结构的成员it_value均赋值为1秒,成员it_interval赋值为3秒即可:
struct itimerval value;
value.it_value.tv_sec=1;
value.it_value.tv_usec=0;
value.it_interval.tv_sec=3;
value.it_interval.tv_usec=0;
setitimer(ITIMER_VIRT, &value, NULL);
例3. 取消一个ITIMER_PROF类定时器。
答:将itimerval结构的成员it_value均赋值为0秒即可:
struct itimerval value;
value.it_value.tv_sec=1;
value.it_value.tv_usec=0;
setitimer(ITIMER_PROF, &value, NULL);
例4. 设置一个定时1.5秒的真实时间定时器,它仅发送一次信号就自动取消。
答:将itimerval结构的成员it_value均赋值为1.5秒,成员it_interval赋值为0秒即可:
struct itimerval value;
value.it_value.tv_sec=1;
value.it_value.tv_usec=500000;
value.it_interval.tv_sec=0;
value.it_interval.tv_usec=0;
setitimer(ITIMER_REAL, &value, NULL);

精确定时器实例

本处设计了一个精确定时器的例子,进程每隔1.5秒数发送定时信号SIGPROF,在接收到信号时将打印定时的次数,用户可以键入CTRL_C或DELETE结束程序,如代码10-11所示:
代码10-11 精确定时器实例(节自/code/chapter10/time4.c)
#include <sys/select.h>
#include <sys/time.h>
#include <stdio.h>
#include <unistd.h>
#include <signal.h>
int n = 0;
void timefunc(int sig)                      /* 定时事件代码 */
{
    fprintf(stderr, "ITIMER_PROF[%d]\n", n++);
}
void main()
{
    struct itimerval value;
    value.it_value.tv_sec=1;                /* 定时1.5秒 */
    value.it_value.tv_usec=500000;
    value.it_interval.tv_sec=1;             /* 定时1.5秒 */
    value.it_interval.tv_usec=500000;
    signal(SIGALRM, timefunc);         /* 捕获定时信号 */
    setitimer(ITIMER_REAL, &value, NULL);   /* 定时开始 */
    while (1);
}
编译和运行代码10-11:
# make time4
        cc -O -o time4 time4.c
# ./time4
ITIMER_PROF[0]
ITIMER_PROF[1]
ITIMER_PROF[2]
ITIMER_PROF[3]

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章