Linux信号与定时器应用实例

程序注册三个定时器,分别对实际时间、进程使用CPU时间、用户使用CPU时间进行即时,计时时间为10秒。同时设定一个用户信号,当该信号在用户指定的空计次循环后到来。在用户信号到来后,打印各个计时器走过的时间值,并计算出内核所用的时间。到实际时间计时器到达10秒后产生定时器信号时,程序打印各计时器走过的时间,并退出程序。

因为需要获得定时器的时间,因此,我们需要使用setitimer和getitimer计时器。使用这两个计时器要频繁的对itimerval和timeval这两个结构体进行操作。首先,应该对这两个结构体在本实例中常用到的操作进行封装。封装的函数包括,timeval的比较,计算两个timeval的时间差,计算itimerval走过的时间(因为itimerval记录的是定时器剩余时间)。为了显示的需要,我们需要封装一个对timeval打印的函数。

之后,我们需要设计信号和信号处理函数,这里我们一共需要两个信号:SIGALRM和SIGUSR1。因为信号处理函数有一个int型参数,该参数可以用来区分信号。考虑到,两个信号到来以后都需要进行时间计算。因此可以考虑将两个信号写成一个函数,通过参数识别,在不同的位置进行不同的处理。


编写程序代码如下:

#include <signal.h>

#include <sys/time.h>

#include <stdlib.h>

#include <stdio.h>


/* 函数声明 */

/* 信号处理函数 */

static void SigHandler(int signo);


/* 操作辅助函数 */

void TimerPassed(const struct itimerval *itimer, struct timeval *tv);

void TimeSubstract(const struct timeval *tv1, const struct timeval *tv2, struct timeval *tvres);

int TimeCompare(const struct timeval *tv1, const struct timeval *tv2);

void PrintTimeval(const char *str, const struct timeval *tv);


/* 主函数,程序入口点 */

int main()

{

    /* 变量声明 */

    struct itimerval myitimer;

    long i, count;


    /* 注册信号处理函数 */

    /* 注册用户信号1处理函数 */

    if (signal(SIGUSR1, SigHandler) == SIG_ERR) {

        printf("Unable to create handler for SIGUSR1\n");

        exit(0);

    }

    /* 定时器信号处理函数 */

    /* 这里将同一个函数注册给两个信号,函数内部存在区分信号类型的逻辑 */

    if (signal(SIGALRM, SigHandler) == SIG_ERR){

        printf("Unable to create handler for SIGALRM\n");

        exit(0);

    }


    /* 运行参数输入 */

    printf("Loop times between timer info outputs (300 Recommanded):\n");

    scanf("%ld", &count);

count *= 1000000;


    /* 初始化定时器参数 */

    myitimer.it_interval.tv_sec = 10;

    myitimer.it_interval.tv_usec = 0;

    myitimer.it_value.tv_sec = 10;

    myitimer.it_value.tv_usec = 0;


    /* 注册定时器 */

    setitimer(ITIMER_REAL, &myitimer, NULL);     /* 实时定时器 */

    setitimer(ITIMER_VIRTUAL, &myitimer, NULL); /* 用户定时器 */

    setitimer(ITIMER_PROF, &myitimer, NULL);     /* CPU定时器 */


    /* 无限循环,等待信号处理 */

    while (1)

    {

        for (i=0; i < count; i++);

        /* 每进行指定次数的循环后,发送用户信号1给自己 */

        raise(SIGUSR1);

    }

}

接下来进行编程:

请见:Linux信号与定时器应用实例训练

邱铁,于玉龙,徐子川.Linux应用与开发典型实例精讲.北京:清华大学出版社.2010年4月