免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1485 | 回复: 0
打印 上一主题 下一主题

一种相对定时器的实现方法 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2010-02-08 17:06 |只看该作者 |倒序浏览
一种相对定时器的实现方法

技术领域
本发明涉及到嵌入式软件开发中的定时器的实现。
背景技术
Linux下我们主要使用三种定时器,它们是alarm()、POSIX:XSI间隔定时器setitimer()、POSIX:TMR间隔定时器timer_create()等,这些定时器都建立在信号触发、处理的基础上,有定时器个数和信号的限制,所以急需要一种定时器摆脱信号处理的束缚,能够在多个操作系统移植的定时器。由此,我们就设计了一个定时器,该定时器作为嵌入式软件应用设计中一个模块,为系统中其它软件应用模块提供了定时功能,它是一个相对的定时器。
该定时器的优点就是方便在不同系统移植,同时该定时器可以给其它多个模块提供定时功能,可以避免进程下使用的定时器时,定时器个数的限制的弊病。该定时器模块适合要求精度不太高的场合。
发明内容
本发明所解决的技术问题是提供一种相对定时器的实现方法,该相对定时器为软件设计中的其它应用模块提供一个相对准确的定时器,而不用完全依赖操作系统提供的定时器。
定时器模块主要提供以下功能:
n         设置定时器:就是设置定时器的时间,并启动定时器。
n         杀死定时器:可以在定时器没有到时的情况,杀死定时器,不再需要定时器定时了。
n         定时器到时上报:设置的定时器到时时,定时器扫描模块发消息给使用定时器的模块,告知该模块使用的定时器到时。
   该相对定时器就是一个等待其它模块申请使用定时器的模块,当其它模块需要使用定时器时,会调用设置定时器接口设置定时器,定时器扫描模块会先查询是否有可用的定时器,如果有,就为该模块分配一个定时器,并且该定时器已经启动,当定时器到时时,定时器扫描模块会以消息的形式发送给使用该定时器的模块,通知定时器已经到时。定时器到时后,该定时器就会死掉,释放了占用的定时器资源,这样定时器模块就多了一个可供分配给其它模块的定时器资源了。
附图说明
图1 定时器滴答数组结构图。
图2 定时器共享内存结构图。
图3 定时器空闲结点表结构图。
图4定时器扫描模块流程图。
图5 设置定时器的流程图。
图6 杀死定时器的流程图。
具体实施方式
定时器模块主要有三个结构来控制、管理定时器,它们是时钟滴答数组、定时器共享内存、定时器空闲结点表。下面具体介绍它们的实施方式。
1)时钟滴答数组
定时器模块有一个时钟滴答数组,数组大小为30000(可配置,用TIMER_MAX_TMCB_NUM表示),数组中每一个组员代表一个10ms(可配置,用TIMER_SLEEP表示)的时间段,数组中各个成员的位置按序为0-29999,并且有一个游标wScanPos指向数组中的某个组员,代表当前的时间,每走过10ms,游标会向前移动一个数组成员,如果要设定一个30ms定时,游标需要前移3个组员时,定时器才会超时,这时,定时器模块会向需要定时的模块发送消息,告知已经到时,定时器就是挂载到该时刻的数组成员下,当游标移动到该数组成员时,就代表了该定时器到时。如图1所示。红色代表30ms的定时器,黄色代表当前游标的位置7,游标需要移动9才到时。所以,定时器就挂载9处。注意,黄色当前游标所在的位置7也算在内,因为游标开始时指向7,但是位置7所代表的10ms时间段并没有走过,所以需要包括在内。
定时器模块通过每隔10ms移动一下游标,然后判断该游标下是否有定时器,如果有定时器,判断定时器是否已经到时,如果到时,就向使用该定时器的模块发送消息,通知该定时器已经到时,因为该游标所指的位置处可能不只一个定时器,定时器模块会将该游标下的到时的定时器通知使用这些定时器的模块。对于大于10ms*30000的定时时间,数组会回到开头循环使用。
在设置定时器时,就一次性确定定时器在10ms时钟滴答数组中到时的位置,定时时间大于10ms*30000的,需要计算该定时器在10ms数组上经过多少轮的循环才会到时。例如,设置一个定时器a,定时的时间为10*60000ms,当前游标的位置在10ms数组的200位置,那么计算定时器a的位置如下:
    dwDly = 10*60000/10;
    dwTime =  200 +  dwDly -1;
dwTimerCounter = (dwDly-1)/30000;
    wPos = dwTime%30000;
其中dwTimerCounter为1,wPos为199,所以定时器a放在10ms数组中位置为199的位置,游标需要两次移动到199位置,定时器才到时。
2)定时器共享内存和定时器空闲结点表
定时器共享内存是一个定时器存储区,里面存储着定时器,包括空闲的定时器和正在使用被占用的定时器,该存储区就是一个定时器的数组。如图2所示。TIMER_MAX_TIMERS为定时器共享内存的定时器的个数。这些定时器的编号按序为0、1、2、……、(TIMER_MAX_TIMERS-1)。
由于定时器要挂载在时钟滴答数组成员下,有可能某个成员下有多个定时器,需要合理方式的管理该成员下的定时器,所以采用双向链表方式将定时器串联起来,每次申请定时器时,都会将这个新定时器放到链表头,然后重新组合链表。每个定时器都有两个变量wPreNode和wNextNode,分别表示在双向链表中前一个定时器和后一个定时器。如图1所示。时钟滴答数组成员就指向这个双向链表的表头。
定时器空闲结点表用来记录定时器共享内存中空闲的定时器在定时器共享内存中的位置,它是一个数组,大小为(TIMER_MAX_TIMERS+1)。空闲结点表有个两个游标wFreeHead、wFreeTail分别指示空闲结点表中的开始位置和空闲结点表结束位置加1。
定时器模块刚启动时,没有定时器被申请,空闲结点表中记录的空闲定时器就是定时器共享内存的中的所有定时器。空闲结点表数组中按序记录着空闲定时器在定时器共享内存中的位置0、1、……. (TIMER_MAX_TIMERS-1),如图3所示。wFreeHead指向空闲结点表的数组成员0,wFreeTail指向空闲结点表的数组成员TIMER_MAX_TIMERS。当其它模块申请设置定时器时,定时器模块从将空闲结点表中第wFreeHead个数组成员中的所指向的定时器分配给该模块,然后wFreeHead加1;当其它模块释放定时器时,空闲结点的第wFreeTail个成员记录该释放的定时器的序号(即该定时器在定时器共享内存中的位置),然后wTailHead加1,例如图3中定时器0、1被申请占用,wFreeHead将移到位置3,虚线所示。当wFreeHead或wFreeTail大于TIMER_MAX_TIMERS时,会将其置0,重新回到起始位置,即这两个游标在空闲结点表上循环移动的。
定时器的个数也是可配置的(用TIMER_MAX_TIMERS表示),一般的情况下100个定时器已经足够使用了,由于定时器是采用静态分配内存的,考虑到有的设备内存较小,可以将定时器个数配置成较小的定时器个数,这样就节省了内存空间。

定时器模块主要包括三个子模块:即设置定时器模块、杀死定时器模块和定时器扫描模块。
1)定时器扫描模块:就是一个扫描时钟滴答数组的模块,该时钟滴答数组各个成员下挂载着定时器,该模块有个游标在时钟滴答数组中移动,当游标移动到这个某个数组成员时,查询该成员下是否有定时器,定时器是否到时,如果到时,就发送消息给使用该定时器的模块,告知它使用的定时器已经到时,同时释放该定时器,修改空闲结点表,否则,游标移动到下一个数组成员。当某个时钟滴答数组成员下有多个定时器时,会逐一判断这些定时器是否到时。游标的移动是每隔一段时间TIMER_SLEEP向前移动一次, TIMER_SLEEP时间大小是可以设置的,游标每走一步的时间是通过延时函数来实现,例如在linux使用usleep()函数时间。下面以一个例子说明,假设游标没走一步时间为10ms,即TIMER_SLEEP为10,则usleep(10*1000),如果设置一个50ms的定时器,则需要移动移动5步定时器才会到时。其流程图如图4所示。
2)设置定时器模块:在定时器模块中申请一个定时器,如果有可分配的定时器模块,那么就根据定时器定时的时间确定定时器在时钟滴答数组中的挂载位置,否则,告知无法设置定时器。
设置定时器的流程图如图5所示。
当申请一个定时器时,需要先查询定时器空闲结点表,是否有空闲的定时器,如果游标wFreeHead等于游标wFreeTail,那么就表示没有空闲的定时器,无法申请一个定时器;否则,就空间结点表成员wFreeHead所指的定时器分配给该模块,并在该定时器上标记已被使用,同时游标wFreeHead加1。然后根据定时器的定时时间dwTime和当前时钟滴答数组的游标wScanPos来计算定时器到时时游标所在的位置,然后将该定时器挂在那个时钟数组成员下,重新组合该时钟滴答数组成员下的定时器链表。
计算定时器挂载位置的公式为:
    dwDly = dwTime/ TIMER_SLEEP;
    dwTime =  wScanPos +  dwDly -1;
dwTimerCounter = (dwDly-1)/ TIMER_MAX_TMCB_NUM;
    wPos = dwTime% TIMER_MAX_TMCB_NUM;
wPos就是定时器挂在时钟滴答数组的位置。dwTimerCounter表示经过wPos位置(dwTimerCounter+1)次时,该定时器才会到时。
3)杀死定时器模块:杀死正在使用的定时器,并释放定时器资源,该定时器资源就可以分配给其它模块使用。
杀死定时器的流程图如图6所示。
当杀死一个定时器时,在该定时器上标记为已空闲,同时将空闲结点表成员wFreeTail指向该定时器,并将游标wFreeTail加1,然后将该成员的下的定时器链表中删除该定时器,重新组合链表。



本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u1/35065/showart_2180222.html
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP