Linux使用一个定时器实现设置任意数量定时器功能
为什么需要这个功能,因为大多数计算机软件时钟系统通常只能有一个时钟触发一次中断。当运行多个任务时,我们会想要多个定时器的时钟跟踪并发这样可以生成正确的时间重叠,操作系统这样做。
本例子是为了实现使用Linux下的一个定时器,实现任一数量的定时器功能。
首先我们需要一些数据类型用来描述时钟数据结构
#include#include #defineTRUE1 #defineFALSE0 #defineMAX_TIMERS...最大时钟数量 typedeftimervalTIME;定义时间类型 #defineVERY_LONG_TIME...最大时间长度 structtimer{ intinuse;时钟是否可用 TIMEtime;定时时间长度 char*event;是否超时 }timers[MAX_TIMERS];/*setoftimers*/
每个定时器都以这个数据结构来描述,第一个成员用来描述时钟是否正在使用,第二个成员是这个定时器的定时时间,第三个成员是是一个指针,*event初始化应该为0,当他被置为1,我们知道这个定时器已经超时了,和他相关的任务可以执行。
接下来是定时器数组的初始化,这里将每个时钟inuse成员设置为FALSE,表示时钟不可用。
void timers_init(){ structtimer*t; for(t=timers;t<&timers[MAX_TIMERS];t++) t->inuse=FALSE; }
现在开始是结构实现部分
首先写到的timer_undeclare这个函数,这个函数与后面的timer_declare相对立。主要作用是清除一个定时器。
有很多方法可以用来保存定时器的定时记录。没有复杂时钟硬件的机器通常在每一个时钟周期处理一个中断处理程序。然后软件就在处理程序中获取系统时间,然后判断是否设置的定时器超时。
很多比较聪明的机器可以在硬件中设置定时时间,一旦时间超时,就触发一个硬件中断。这同样适用与软件中断。
他们通过一个定义一个time_now来记录当前的系统时间,volatile告诉机器每次从寄存器取值,防止数据被系统优化。
volatileTIMEtime_now
接下来定义一系列数据来记录timer_next指接下来要我们想要计时的定时器。time_timer_set保存最后一次获取的系统时间。
structtimer*timer_next=NULL;/*timerweexpecttorundownnext*/ TIMEtime_timer_set;/*timewhenphysicaltimerwasset*/ //取消一个定时器 voidtimer_undeclare(structtimer*t) { disable_interrupts(); if(!t->inuse) { enable_interrupts(); return; } t->inuse=0; if(t==timer_next) { if(time(&time_now)<0) perror("timeerror"); timers_update(time_now-time_timer_set); if(timer_next) { start_physical_timer(&timer_next->time); time_timer_set=time_now; } } enable_interrupts(); }
timer_undeclare作用为取消一个定时器。首先让中断失效,这很重要,因为时钟数据结构数据是在各进程中共享的,是可以在其他中断中被修改的,为了防止不必要的错我,这个取消操作应该为一个原子操作。开始我们先检测是否这个时钟已经无效了。如果有效,则设置inuse使其失效。如果我们要取消的定时器正好是下一个期望等待的定时器。那我们要重新指定下一个期望等待的定时器。在此之前所有定时器都要更新一下前一个定时器已经走过的时间。
接下来我们看到timers_update(time_tti)函数
//更新定时器表时间 voidtimers_update(time_ttime) { staticstructtimertimer_last={ 0, {}, NULL }; timer_last.time.tv_sec=10; structtimer*t; timer_next=&timer_last; for(t=timers;t<&timers[MAX_TIMERS];t++) { if(t->inuse) { if(timetime.tv_sec){ t->time.tv_sec-=time; if(t->time.tv_sec<\ timer_next->time.tv_sec) timer_next=t; }else { *(t->event)=1; t->inuse=0; } } } if(!timer_next->inuse)timer_next=0; }
此函数作用是更新所有有效定时器的时间长,同时将timer_next指向当前延时时间最短的一个定时器。如没有定时器,则将timer_next设置为空。
timer_declare加入一个定时器
structtimer*timer_declare(TIME*ti,char*event) { structtimer*t; disable_interrupts(); for(t=timers;t<&timers[MAX_TIMERS];t++) { if(!t->inuse)break; } if(t==&timers[MAX_TIMERS]) { enable_interrupts(); return0; } t->event=event; t->time.tv_sec=ti->tv_sec; t->time.tv_usec=ti->tv_usec; if(!timer_next) { if(time(&time_now)<0) perror("time()error"); time_timer_set=time_now; start_physical_timer(&((timer_next=t)->time)); }elseif((ti->tv_sec+time_now)<(\ timer_next->time.tv_sec+time_timer_set)) { if(time(&time_now)<0) perror("timeerror"); timers_update(time_now-time_timer_set); time_timer_set=time_now; start_physical_timer(&((timer_next=t)->time)); }else { } t->inuse=1; enable_interrupts(); returnt; }
首先找到一个可用的定时器表项,设置相关参数。
接下来判断如果timer_next为空,那么说明定时器表项没有定时器需要定时,那我们直接将timer_next指向新加入定时器,开始计时。
如果新加入定时器需要延时时间比当前正在延时的定时器的剩余时间还要短,则更新定时器表,并计时当前加入的定时器。
在处理完当前定时器事件后,将新加入的定时器的inuse置1.
接下来是定时器中断处理函数
//定时器中断处理函数 voidtimer_interrupt_hander(intsigno) { printf("interrupt_hander\n"); if(time(&time_now)<0) perror("time()error"); timers_update(time_now-time_timer_set); if(timer_next) { time_timer_set=time_now; start_physical_timer(&timer_next->time); } }
这里我们打印一串字符来证明定时器时间的触发,首先要做的先更新定时器表,然后将time_timer_set设置成当前系统时间,继续进行下一个定时器事件,直到所有定时器都处理完毕。
接下来几个是LINUX系统相关函数
//失效定时器中断 voiddisable_interrupts() {sigset_tnew_mask; sigemptyset(&new_mask); sigaddset(&new_mask,SIGALRM); if(sigprocmask(SIG_BLOCK,&new_mask,NULL)<0) perror("SIG_BLOCKerror"); } //使能定时器中断 voidenable_interrupts() { sigset_tnew_mask; sigemptyset(&new_mask); sigaddset(&new_mask,SIGALRM); if(sigprocmask(SIG_UNBLOCK,&new_mask,NULL)<0) perror("SIG_UNBLOCKerror"); } //开启一个定时器工作 voidstart_physical_timer(TIME*time) { if(signal(SIGALRM,timer_interrupt_hander)==SIG_ERR) perror("signalerror"); structitimervalnew_value; sigset_tzero_mask; sigemptyset(&zero_mask); new_value.it_value.tv_sec=time->tv_sec; new_value.it_value.tv_usec=time->tv_usec; new_value.it_interval.tv_sec=0; new_value.it_interval.tv_usec=0; setitimer(ITIMER_REAL,&new_value,NULL); sigsuspend(&zero_mask); }
主函数测试部分
#include#include #include"multtime.h" #include #include intmain() { pid_tpid; TIMEtime1,time2,time3; time1.tv_sec=6; time1.tv_usec=0; time2.tv_sec=4; time2.tv_usec=0; time3.tv_sec=2; time3.tv_usec=0; timer_init(); if((pid=fork())<0) { perror("fork()error"); } elseif(pid==0) { printf("child1\n"); timer_undeclare(timer_declare(&time1,0)); } else { if((pid=fork())<0) { perror("forkerror"); } elseif(pid==0) { printf("child2\n"); timer_undeclare(timer_declare(&time3,0)); } else { printf("parent\n"); timer_undeclare(timer_declare(&time2,0)); } } exit(0); }
实验结果:
parent child2 child1 interrupt_hander interrupt_hander interrupt_hander
总结
以上所述是小编给大家介绍的Linux使用一个定时器实现设置任意数量定时器功能,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。