嵌入式学习笔记 - freeRTOS 阻塞延时的实现机制,同时避免在中断中扫描停留
一 freeRTOS 阻塞延时到期激活的实现机制,同时避免在中断中扫描停留
任务在激活阻塞时先根据延时时间赋值NextTaskUnlockTime,再扫描延时列表的所有节点,然后根据延时时间确定插入链表的什么位置,如下图:
上图中横线就是任务启动延时时,将任务节点插入延时列表激活阻塞
上图中横线就是通过轮询方式查找位置并插入,如下图函数具体实现中的for语句,可见delayedlist延时列表的两个链表里节点都是按照延时时间顺序排列的因为插入的时候是按照顺序插入的。(题外话:而就绪列表里的节点并不是按照顺序插入的,因为优先级都一样,每次都是直接插入链表末端使用的插入函数是vListInsertEnd,所以就绪列表里的节点的辅助值没什么意义)。
systick中断只需根据NextTaskUnlockTime激活延时列表的第一个节点即可(激活是通过删除延时列表节点并添加到就绪列表的的方式,有可能不止一个节点但是肯定靠在前面),按大小插入延时列表肯定要排序,
这样就把扫描排序交给任务了,避免了在中断中停留太久的问题。如下图:
二 总结
freeRTOS实现阻塞延时的方式就是对两个延时列表进行扫描操作
加入延时列表时,扫描延时列表,根据延时值顺序插入延时列表,
退出延时列表时,不需要扫描,直接从第一个任务节点开始边判断边从延时列表删除相应的节点,直到xConstTickCount < xItemValue。
两个延时列表形成互补防止时基溢出交界之时无法处理的问题。
static List_t xDelayedTaskList1;
static List_t xDelayedTaskList2;
static List_t * volatile pxDelayedTaskList;
static List_t * volatile pxOverflowDelayedTaskList;
注意这里定义两个延时链表的方式也很巧妙,分别定义了两个链表变量,然后定义了两个链表指针,分别指向两个链表,这样可以灵活的运用两个指针,当想要操作的对象改变时只需要对指针交换指针指向的地址即可。