嵌入式技术论坛
直播中

ss

7年用户 8762经验值
擅长:电源/新能源 制造/封装 RF/无线
私信 关注
[问答]

怎样去使用在RTOS中的系统延时定时器Timer队列呢

在任何一个RTOS中,都免不了系统延时定时器timer队列,在系统延时、等待事件等之时都是通过它触发任务切换,uc/osii和rtt中也不例外。但在uc/osii和rtt中都不约而同地选择了实现简单但效率极低的尾部添加模式,即一旦有任务调用了 delay系统功能,操作系统就把当前的任务资料以及需要延时的系统tick数追加到定时器队列的尾部,在定时器任务得到运行时,一个一个依次查询每个任务的延时是否已经到达,若已到则唤醒任务(但不会马上切换到该任务),然后再查询下一个任务的延时状态。如果正处于延时状态的任务数量比较多,那么这将是一个很耗时很低效的过程。个人觉得应该修改这个算法,在每一次增加一个定时器之时,把需要的延时ticks数与队列中已有定时器的延时数作比较,算出其差值,再将该任务信息插入到队列中合适的位置。举例为说,假如第一次一个任务要延时30,则队列中只有一个延时任务,延时数为30。第二次另一个任务要延时20(假如此时还没有运行过定时器任务),则把第二个任务排在第一位,原任务的延时数改为10(30-20=10,表示在第一个任务完成后还要延时10个ticks。如果还有第三个任务需要延时40,则40-20-10=10,它的延时数也修正为10,并追加到队列最后。因为这样的遍历只需要在增加一个延时任务之时才运行,而在定时器任务中,每次只需要检查第一个任务的延时是否已经到达(如果已经到达则需要检查它后面的任务是否也已到达),勿需再遍历队列中的每个任务,效率将得到明显提高。以伪语言描述如下:
修改前:
dalay(...)
{
add task to delay_list
delay_list.task.delay = dlay_time
task_schedule()
}
timer_task(...)
{
for(i = 0; i < MAX_TIMERS; i++)
{
if(delay_list.task is valid)
{
if(0 == (--delay_list.task.delay))
{
set task.status to active
delete task from delay_list
}
}
}
task_schedule()
}
修改后:
dalay(...)
{
pLast, pNext // 指向定时器队列的指针
pLast = First, pNext = pLast->Next
for(i = 0; i < MAX_TIMERS; i++)
{
if(pLast->task is valid)
{
if(delay_time > pLast->task->delay)
{
delay_time -= pLast->task->delay
}
else
{
this task->Next = pLast->task->Next // insert task to delay_list
pLast->task->Next = this task
this task->delay = delay_time
exit loop
}
task_schedule()
}
}
}
timer_task(...)
{
First->task->delay--
while(0 == First->task->delay)
{
set First ->task->status to active
First = First ->task->Next // delete task from delay_list
}
task_schedule()
}
First是指向系统定时器队列第一个元素的指针。
因为比较绕,我担心没有讲清楚,但愿通过伪语言有助于大家的理解。

回帖(4)

ss

2022-3-23 09:17:46
此方法就是COOCOX的OS Timer处理机制,比较高效!
举报

ss

2022-3-23 09:17:53
for循环或while循环并不意味着遍历,建议lz还是仔细琢磨代码。
举报

ss

2022-3-23 09:18:00
事实上,rtt已经作了排序优化。
举报

ss

2022-3-23 09:18:12
我觉得不仅仅是排序优化这么简单。例如按照存放差值排序的方式,如果把timer列表中的一个节点给删除会出现什么样的情况?将对以删除节点为起点,直到末尾的增量差值进行调整 。
举报

更多回帖

发帖
×
20
完善资料,
赚取积分