在网上学习 FreeRTOS 列表后做的一些笔记和总结,仅供学习交流。
目录
列表简介
FreeRTOS 中任务有多种状态:就绪态、运行态、阻塞态、挂起态。当存在多个任务都处于某个状态时,为了方便处理这些任务,会把这些任务组成一个列表。
列表,是 FreeRTOS 系统创建的一个结构体(底层是一个数据结构,跟链表有点类似,可以把列表看成链表中的链表头,不过链表头一般只存放下一个结构体地址,而列表存放着更多的信息),由多个相同状态的任务(以列表项的形式存放)组成(列表内的指针指向多个列表项),用于对任务的跟踪和处理。
列表分为三大类:
就绪列表
阻塞列表
挂起列表
任务的每一种状态都会有一个列表,就绪态的任务就有一个列表项位于就绪列表中。
为什么运行态没有列表?
因为每次只有一个任务是运行态,所以根本不需要列表。
列表的定义
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /* 校验值 */
volatile UBaseType_t uxNumberOfItems; /* 列表中的列表项数量 */
ListItem_t * configLIST_VOLATILE pxIndex /* 用于遍历列表项的指针 */
MiniListItem_t xListEnd /* 末尾列表项 */
listSECOND_LIST_INTEGRITY_CHECK_VALUE /* 校验值 */
} List_t;
1)listFIRST_LIST_INTEGRITY_CHECK_VALUE、listSECOND_LIST_INTEGRITY_CHECK_VALUE:
这两个宏是确定的已知常量, FreeRTOS 通过检查这两个常量的值,来判断列表的数据在程序运行过程中,是否遭到破坏 ,该功能一般用于调试, 默认是不开启的。
2)uxNumberOfItems:用于记录列表中列表项的个数(不包含 xListEnd)。
3)pxIndex:指向列表中的某个列表项,一般用于遍历列表中的所有列表项。
4)xListEnd:末尾列表项(或迷你列表项),排在列表项的最末尾,表示列表的结束位置,给其他列表项起到一个定位的作用。
列表项的定义
typedef struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /* 用于检测列表项的数据完整性 */
configLIST_VOLATILE TickType_t xItemValue /* 列表项的值 */
struct xLIST_ITEM * configLIST_VOLATILE pxNext /* 下一个列表项 */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious /* 上一个列表项 */
void * pvOwner /* 列表项的拥有者 */
struct xLIST * configLIST_VOLATILE pxContainer; /* 列表项所在列表 */
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /* 用于检测列表项的数据完整性 */
} ListItem_t;
1)xItemValue:列表项的值,这个值多用于按升序对列表中的列表项进行排序。
2)pxNext 和 pxPrevious:分别用于指向列表中列表项的下一个列表项和上一个列表项。
3)pxOwner:指向拥有该列表项的对象。通常是指向任务控制块,每个任务都有属于自己的任务控制块,里面一般就有一个列表项。
任务控制块(简称 TCB,是一个结构体)是任务的身份证,每个任务都有一个属于自己的 TCB,里面存有任务的所有信息,比如任务的状态、任务的优先级、任务的栈指针、任务名称、任务的形参等。TCB 里面存放的信息是提供给系统使用的,系统对这个任务的所有操作,都是通过这个任务控制块里面存放的信息来实现的,比如根据优先级进行任务切换等等。
4)pxContainer:指向列表项所在列表,例如就绪列表。列表项都是一个个独立的结构体,如果不用指针指向,根本不知道这个结构体跟列表有什么关系。
每个列表项对应一个任务。
迷你列表项的定义
typedef struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /* 用于检测数据完整性 */
configLIST_VOLATILE TickType_t xItemValue; /* 列表项的值 */
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /* 上一个列表项 */
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /* 下一个列表项 */
} MiniListItem_t;
1)xItemValue:列表项的值,这个值多用于按升序对列表中的列表项进行排序。
2)pxNext 和 pxPrevious:分别用于指向列表中列表项的下一个列表项和上一个列表项。
迷你列表项,又称末尾列表项,只用于标记列表的末尾和挂载其他插入列表中的列表项,因此不需要成员变量 pxOwner 和 pxContainer,以节省内存开销。
列表、列表项、迷你列表项、TCB 之间的关系
从图中可以看出,多个列表项组成了一个双向链表,列表中指向该双向链表中任意一个列表项和末尾列表项,因为列表的任意指向列表项这个特性,所以只要有列表,就可以实现列表项的增删查改功能,从任意位置中插入或删除列表项,查询或修改任意位置的列表项。
列表项间的地址非连续的,是人为的连接到一起的。列表项的数目是由后期添加的个数决定的,随时可以改变。在操作系统中任务的数量是不确定的,随时都有可能加任务或者删任务,并且任务状态是会发生改变的(例如就绪态的任务变成阻塞态,就会从就绪列表转移到阻塞列表),所以非常适用列表(即链表)这种数据结构,才用列表的方式去处理数据。
添加列表项的过程图示:
列表刚被创建时,只有三个初始成员:uxNumberOfItems、*pxIndex、xLiseEnd (末尾列表项)。末尾列表项的作用就类似于坐标,作为其他列表项的坐标,让它们来挂载连接,这样才能变成链表,如下