《野火RT-Thread内核实现与应用开发实战》笔记6. 定时器的实现

1. 前期回顾

在本章之前,为了实现线程的阻塞延时,在线程控制块中内置了一个延时变量remaining_tick。每当线程需要延时的时候,就初始化 remaining_tick 需要延时的时间, 然后将线程挂起,这里的挂起只是将线程在线程就绪优先级组中对应的位清 0,并不会将线程从线程优先级表(即就绪列表)中删除。 当每次时基中断(SysTick 中断) 来临时, 就扫描就绪列表中的每个线程的 remaining_tick, 如果 remaining_tick 大于 0 则递减一次,然后判断 remaining_tick 是否为 0,如果为 0 则表示延时时间到,将该线程就绪(即将线程在线程就绪优先级组中对应的位置位) ,然后等待系统下一次调度。 这种延时的缺点是,在每个时基中断中需要对所有线程都扫描一遍,费时,优点是容易理解。

在 RT-Thread 中,每个线程都内置一个定时器,当线程需要延时的时候, 则先将线程挂起,然后内置的定时器就会启动, 并且将定时器插入到一个全局的系统定时器列表rt_timer_list,这个全局的系统定时器列表维护着一条双向链表,每个节点代表了正在延时的线程的定时器,节点按照延时时间大小做升序排列。 当每次时基中断(SysTick 中断) 来临时, 就扫描系统定时器列表的第一个定时器, 看看延时时间是否到, 如果到则让该定时
器对应的线程就绪, 如果延时时间不到, 则退出扫描, 因为定时器节点是按照延时时间升序排列的, 第一个定时器延时时间不到期的话, 那后面的定时器延时时间自然不到期。 比起第一种方法,这种方法就大大缩短了寻找延时到期的线程的时间。

2. 核心知识点

定时器的实现内容较多,具体分析可参考工程源码,此时只记录调试过程中的核心知识点

  1. 每个线程控制块中内置了一个定时器控制块,当线程第一次调用延时函数时,该线程内的定时器控制块会通过双向链表节点挂载到全局定时器列表(rt_timer_list[RT_TIMER_SKIP_LIST_LEVEL])的一条双向链表上。而且根据每个定时器控制块的超时时长,按照升序进行挂载,比如线程1延时40ms,线程2延时20ms,线程3延时30ms,1个系统节拍为10ms,则这三个线程启动延时时,定时器列表初始挂载状态如下图所示:
    在这里插入图片描述

  2. 每个定时器控制块如何实现延时到期判断?

    定时器控制块中含有init_tick和timeout_tick两个32位无符成员变量,init_tick表示实际需要延时的时间,timeout_tick表示实际延时到期时的系统节拍数,比如线程1在某个位置调用延时函数,传入延时值2,延时函数内部会设置init_tick为2,然后启动定时器,在启动定时器的函数中,会自动根据当前系统节拍数n初始化timeout_tick的值为n+2,后面只需要比较当前系统节拍数是否大于等于timeout_tick的值,如果是则表明延时到期。

  3. 实现定时器的整体框架?

    • 线程调用延时函数时,将启动该线程的内置定时器,会将内置定时器控制块挂载到定时器列表的一条双向链表上,其它线程调用延时函数也同样将其它线程的内置定时器控制块挂载到这条双向链表。同时该线程会被设置为挂起状态,从线程优先级列表中移除,线程就绪优先级组中对应的位清零。最后立即执行系统调度。
    • 周期性进入的系统时基(SysTick)中断处理函数会将系统节拍(rt_tick)加1,同时扫描系统定时器列表,从双向链表的根节点开始,依次比较每个定时器节点是否延时到期,如果到期则执行该定时器控制块的函数指针成员指向的函数,执行完成后继续扫描下一个定时器节点;否则就跳出扫描,不用继续扫描后面的定时器了,因为定时器是按照延时升序挂载的,前面的都没到期,后面的肯定也没到期。
    • 线程超时函数会将该线程恢复为就绪状态,将该线程插入优先级列表,将线程就绪优先级组中对应的位置位,然后执行系统调度。
  4. 调试程序时发现PendSV_Handler()的优先级低于SysTick_Handler()的优先级,当在SysTick_Handler()中发起线程切换时,不会立即进入PendSV_Handler()处理上文保存和下文切换,而是要等到SysTick_Handler()退出了才会进入。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值