FreeRTOS列表和列表项(链表)

FreeRTOS列表和列表项(链表)

列表就是链表,提供给任务的不同状态使用不同的列表,如就绪列表、阻塞列表等。
列表即:就是一个链表,实现:一个结构,包含指向链表节点的指针,链表长度等;就绪表,阻塞(延时)表,挂起表等
列表项即:链表节点,一个数据结构(数据域,指针域(不仅仅包含前驱后继指针,还包含指向该节点所在的TCB和指向所在链表的两个指针))。
每个任务tskTCB都包含一个列表项(链表节点),用于表示任务的状态。

FreeRTOS列表的实现在list.c和list.h中。

有三个关键性结构:ListItem_t,MiniListItem_t,List_t;
ListItem_t:包含所在结构的指针,和所在链表的指针。
MiniListItem_t:作为链表中哨兵,无实际意义。
List_t:链表结构
通过链表遍历只能找到链表节点ListItem_t,需要再通过ListItem_t中的指针pvOwner就才能找到它所在的TCB结构。

vListInitialise:链表初始化时,将指针pxIndex指向mini节点xListEnd,mini节点xListEnd自循环,链表长度设为零。
vListInsert:链表插入操作,从xListEnd开始遍历链表找到最小xItemValue值节点的前一个节点,然后从该节点向后插入;即:使用该链表插入函数,使得链表根据xItemValue值升序排列。同时将节点内指向所插入的链表的指针和链表长度更新
vListInsertEnd:通过指针pxIndex,插入当前头节点的前面(该头节点就是pxIndex指向的节点,该指针会移动),即:链表的尾部。主要用于就绪链表的插入。
uxListRemove:形参必须是TCB数据类型,即:任务类型;实现:通过TCB找到此时任务所在的链表(该结构中的指针pvContainer指向该任务所在的链表,删除过后需要将pvContainer置为NULL),然后对该链表进行删除节点操作。返回链表当前节点数量。、

一、vListInsert与vListInsertEnd区别?
前者升序插入,后者从当前头节点之前插入。
二、pxCurrentTCB在哪里更新的???
在函数vTaskSwitchContext中的宏taskSELECT_HIGHEST_PRIORITY_TASK进行更新(先通过变量uxTopReadyPriority定位数组pxReadyTasksLists[]中的指向对应优先级列表项的指针,从而查找当前就绪列表中优先级最高的任务),即:获取当前需要运行的任务。vTaskSwitchContext函数在服务函数xPortPendSVHandler中进行跳转调用(bl vTaskSwitchContext),
三、uxTopReadyPriority对应优先级位何时恢复(变为0)?
在对应优先级任务全部从对用优先级就绪列表中删除后(每次删除操作之后,都会调用taskRESET_READY_PRIORITY)
四、列表是否是循环队列?就绪列表,延时(阻塞)列表,挂起列表的实现
1)就绪列表
就绪列表是一个循环队列。每个优先级任务都有一个就绪表(即:不同优先级任务使用不同就绪表,同一个优先级任务使用同一个就绪表,这样有助于相同优先级任务时间片调度代码的编写),表头在数组pxReadyTasksLists[]中,每次和uxTopReadyPriority配合使用。
pxReadyTasksLists[]初始化的时候将pxIndex指针指向了mini列表项xListEnd(就是一个哨兵的作用,遍历到这里就要跳过),插入操作使用了vListInsertEnd(每次插入都是在当前运行任务的前面,即:队列的尾,即新插入的同优先级的任务最后执行,调用listGET_OWNER_OF_NEXT_ENTRY开始轮询队列;删除操作在任务进入阻塞列表或者挂起的时候,即:调用vTaskDelay()、vTaskDelayUntil()和vTaskSuspend()时候。
pxReadyTasksLists[]和uxTopReadyPriority配合使用:uxTopReadyPriority的每一位表示就绪列表中的某个优先级任务是否存在,即:置位该变量的对应位,代表就绪列表中存在这一个优先级的任务,例:最低位表示空闲任务是否在就绪,如下图。
在这里插入图片描述
同一优先级任务调度:
在这里插入图片描述

2)延时(阻塞)列表
是个循环链表,不是队列。针对计数器溢出问题,FreeRTOS给出了两个延时列表,一个计数未溢出时使用,一个计数溢出时使用,以vListInsert形式插入。当计数器xTickCount溢出时,两个分别指向延时表和溢出延时表的指针会互换。
这里xListEnd就是一个标记的作用,从xListEnd开始遍历,通过列表项值xItemValue进行升序插入。每次进入滴答定时器服务函数,都会比较表头的延时时间xItemValue是否达到现在的计数时间xTickCount,如果达到就将表头对应的任务从延时列表中移除(条件:当前计数值大于等于下一次需要解锁时的计数值xNextTaskUnblockTime(这个值是会更新的))。
xDelayedTaskList1存放唤醒计数值xItemValue未溢出的任务,xDelayedTaskList2存放唤醒计数值xItemValue溢出的任务。
在这里插入图片描述
3)挂起列表
调用vTaskSuspend()函数实现任务的挂起,形参为任务指针,如果形参为NULL,则将挂起当前正在运行的任务。将任务从其当前链表中移除,插入到挂起链表。
vTaskSuspendAll:挂起调度器操作,++uxSchedulerSuspended,在滴答定时器服务函数中截断,不进行延时链表到就绪链表操作。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值