在linux下实现精度较高的定时功能,需要用到setitimer 和 getitimer函数。
函数原型:
#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);
· 函数getitimer()把指定的定时器类型( ITIMER_REAL, ITIMER_VIRTUAL, 或 ITIMER_PROF中的一个)写入curr_value指向的结构。
it_value设置为定时器剩余时间(若定时器关闭则为0)。类似的,it_interval设置为复位时间。
分析形参:
1. int which
which为定时器类型,setitimer支持3种类型的定时器:
ITIMER_REAL: 以系统真实的时间来计算,它送出SIGALRM信号。
ITIMER_VIRTUAL: -以该进程在用户态下花费的时间来计算,它送出SIGVTALRM信号。
ITIMER_PROF: 以该进程在用户态下和内核态下所费的时间来计算,它送出SIGPROF信号。
2. const struct itimerval *value
value 是一个指向itimerval类型的指针,介绍如下
struct itimerval { struct timeval it_interval;//next value struct timeval it_value;//current value };
timeval也是一个数据类型:
struct timeval { long tv_sec; long tv_usec; };
it_interval指定间隔时间,it_value指定初始定时时间。如果只指定it_value,就是实现一次定时;如果同时指定 it_interval,则超时后,系统会重新初始化it_value为it_interval,实现重复定时;两者都清零,则会清除定时器。tv_sec提供秒级精度,tv_usec提供微秒级精度,以值大的为先。
3. struct itimerval *ovalue
ovalue用来保存先前的值,通常设置为NULL。
每次定时循环结束会产生中断,通常会用到signal函数捕捉处理,原型为:
#include<signal.h> void (* signal(int sig, void (*func) (int)) ) (int);
signal()是一个系统调用,常用来设定某个信号(sig)的处理方法(func):
信号类型(sig)
(1) 与进程终止相关的信号。当进程退出,或者子进程终止时,发出这类信号。
(2) 与进程例外事件相关的信号。如进程越界,或企图写一个只读的内存区域(如程序正文区),或执行一个特权指令及其他各种硬件错误。
(3) 与在系统调用期间遇到不可恢复条件相关的信号。如执行系统调用exec时,原有资源已经释放,而目前系统资源又已经耗尽。
(4) 与执行系统调用时遇到非预测错误条件相关的信号。如执行一个并不存在的系统调用。
(5) 在用户态下的进程发出的信号。如进程调用系统调用kill向其他进程发送信号。
(6) 与终端交互相关的信号。如用户关闭一个终端,或按下break键等情况。
(7) 跟踪进程执行的信号。
下列宏常量表达式指定了标准的信号值:
Marcro | Signal |
SIGABRT | 异常终止,如调用abort(). |
SIGFPE | 如除0或操作结果溢出(不一定是浮点操作). |
SIGILL | 非法指令或无效的函数镜像,通常由于代码错误或执行数据引起. |
SIGINT | 交互式中断信号,通常由用户产生. |
SIGSEGV | 段冲突.访问非法存储空间时产生. |
SIGTERM | 发给本程序的中止信号. |
处理方法(func)有三种,分别是:
默认处理(SIG_DFL), 信号以其默认指定的行为进行处理。
忽略信号(SIG_IGN), 信号被忽略而且程序会继续往下执行,即使没有任何意义。
函数处理,以用户指定的函数来处理信号。
仅看原型比较抽象,举个例子就知道了:
#include<stdio.h> #include<sys/time.h> #include<signal.h> void response(void); int main() { struct itimerval my_timer; long n_sec, n_usec; my_timer.it_interval.tv_sec = 0; my_timer.it_interval.tv_usec = 300*1000;//300ms my_timer.it_value.tv_sec = 2; //2s my_timer.it_value.tv_usec = 0; setitimer(ITIMER_REAL, &my_timer, NULL); signal(SIGALRM,(__sighandler_t)&response); while(1) ; return 0; } void response(void) { printf("Receive signal!!\n"); }
上述代码片段将定时器初始值设为2s,循环值为300ms,则当setitimer函数执行以后2s产生SIGALRM中断,由signal函数指定中断处理函数为response();
2s之后,每隔300ms产生一次SIGALRM中断。
参考文章:
http://www.uml.org.cn/c%2B%2B/200812083.asp