感谢支持
我们一直在努力

Linux应用程序中的定时器

Linux操作系统为每一个进程提供了3个内部计时器。


ITIMER_REAL;ITIMER_VIRTUAL;ITIMER_PROF.


ITIMER_REAL:给定一个指定的时间间隔,按照实际的时间来减少这个计数,当时间间隔为0的时候发出SIGALRM信号。


ITIMER_VIRTUAL:给定一个时间间隔,当进程执行的时候才减少计数,时间间隔为0的时候发出SIGVTALRM信号。


ITIMER_PROF:给定一个时间间隔,当进程执行或者是系统为进程调度的时候,减少计数,时间到了,发出SIGPROF信号,这个和TIMER_VIRTUAL联合,常用来计算系统内核时间和用户时间。


看一下getitimer的数据手册


getitimer, setitimer – get or set value of an interval timer


#include <sys/time.h>


int getitimer(int which, struct itimerval *value);


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


ITIMER_REAL;ITIMER_VIRTUAL;ITIMER_PROF.就是三个定时器,在使用的时候,当其中的任何一个时间到了,都会给进程发送一个信号,然后定时器重新被装填,重新开始定时动作。


它们对应的信号


ITIMER_REAL    —- SIGALRM


ITIMER_VIRTUAL —- SIGVTALRM


ITIMER_PROF    —- SIGPROF


函数中的which就是选择这三个定时器中的一个。


下面是描述时间结构体value的


struct itimerval {


struct timeval it_interval; //下一个值


struct timeval it_value;    //当前的值


};


struct timeval {


long tv_sec;  //秒


long tv_usec; //毫秒


};


一个表示时间的结构体,一个含有时间结构体的结构体。


使用定时器的时候,首先定义一个时间结构体,然后初始化这个时间结构体的秒和毫秒。然后使用setitimer函数,第一个参数指定使用哪一个定时器,第二个参数就是传递进去的时间结构体,第三个参数为NULL。这样就设定好了一个定时器了。它就可以开始工作了。


说一下返回值: 函数调用成功返回0, 错误返回-1,并且设置出错值errno。


当出错的时候:可能是value或者是ovalue指针无效;或者是定时器搞错了,不是这三个中的一个;或者是时间结构体中的毫秒超出了0到999999的范围。


由于当定时器的时间到了的时候会引发一个信号,因此我们必须对信号进行处理,因此需要了解一下信号处理的函数。


我们可以修改Linux系统信号的相关联的动作,也就是当捕获到某个信号时需要执行什么函数。有点像是可以更改函数指针指向的函数一样。


有这么一个函数可以完成这个问题:sigaction。


也就是sig-action,signal-action,信号动作。


#include<sginal.h>


int sigaction(int signo, const struct sigacton *rstrict act, struct sigaction *restrict oact);


这个函数具有三个参数,第一个是信号的名字,直接写系统的信号名,比如SIGALRM之类的。第二个参数是一个结构体,表述了信号相关的东西,我们修改的函数指针就在里面。第三个函数是用来返回的,返回该信号的上一个动作,也就是上一个这个信号结构体里面的函数指针指向的函数。

下面看一下这个信号结构体。


struct sigaction {


void (*sa_handler)(int);


sigset_t sa_mask;


int sa_flags;


void (*sa_sigaction)(int, siginfo_t *, void *);


};


在使用的时候,sa_handler和sa_sigaction只是用一个。


sa_mask是和sa_handler一起的。


sa_mask表示了一个信号集合,在调用sigaction之前要先用sigemptyset把sa_mask加入到进程的信号屏蔽字当中。


sigemptyset函数初始化一个sigset_t *类型的信号集合,清除里面的所有信号。


使用函数sigaction(SIGALRM, &tact, NULL)就是把SIGALRM的信号的触发动作变成tact结构体中的sa_handler或者sa_sigaction所指向的函数了。


例子如下,每隔2秒钟打印一行字。


一个函数用来设置信号相关的函数绑定,一个函数用来初始化定时器并且启动它。


然后程序需要运行很久,放到死循环里面去,才能看出来效果,一般的应用程序,都不会自动退出的,往往是永远不退出,或者是等待用户关闭它。



  1. #include<sys/time.h>   

  2. #include<stdio.h>   

  3. #include<unistd.h>   

  4. #include<signal.h>   

  5. #include<string.h>   

  6. static char msg[] = “time is running out.\n”;   

  7. static int len;   

  8. void prompt_info(int signo)   

  9. {   

  10.     write(STDERR_FILENO, msg, len);   

  11. }   

  12. void init_sigaction(void)   

  13. {   

  14.     struct sigaction tact;   

  15.     tact.sa_handler = prompt_info;   

  16.     tact.sa_flags = 0;   

  17.     sigemptyset(&tact.sa_mask);   

  18.     sigaction(SIGALRM, &tact, NULL);   

  19. }   

  20. void init_time()    

  21. {   

  22.     struct itimerval value;   

  23.     value.it_value.tv_sec = 2;   

  24.     value.it_value.tv_usec = 0;   

  25.     value.it_interval = value.it_value;   

  26.     setitimer(ITIMER_REAL, &value, NULL);   

  27. }   

  28. int main()   

  29. {   

  30.     len = strlen(msg);   

  31.     init_sigaction();   

  32.     init_time();   

  33.     while(1);   

  34.     exit(0);   

  35. }  

赞(0) 打赏
转载请注明出处:服务器评测 » Linux应用程序中的定时器
分享到: 更多 (0)

听说打赏我的人,都进福布斯排行榜啦!

支付宝扫一扫打赏

微信扫一扫打赏