FreeRTOS通用链表解析
1.核心结构体
List_t 是链表本身,管理链表。
ListItem_t 是“正常节点”,用来挂载任务等对象。
MiniListItem_t 是“精简节点”,专门当链表的“哨兵/结束标记”。
ListItem_t |
普通节点 |
|
真正存储任务/对象的节点 |
MiniListItem_t |
精简节点 |
|
链表头尾的哨兵节点 |
List_t |
容器 |
|
管理整个链表,带有结束标记 |
struct xLIST_ITEM ListItem_t
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< 当 configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设为 1 时,设置为已知值,用于链表项数据完整性校验。*/
configLIST_VOLATILE TickType_t xItemValue; /*< 链表项的排序值。多数情况下用于链表降序排序,可表示任务优先级、超时时间等。*/
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< 指向链表中的下一个 ListItem_t 类型链表项。*/
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< 指向链表中的上一个 ListItem_t 类型链表项。*/
void * pvOwner; /*< 指向包含该链表项的对象(通常是 TCB 等),建立链表项与所属对象的双向链接。*/
void * configLIST_VOLATILE pvContainer; /*< 指向该链表项所在的链表(若已加入链表)。*/
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< 当 configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设为 1 时,设置为已知值,辅助链表项数据完整性校验。*/
};
typedef struct xLIST_ITEM ListItem_t;
struct xMINI_LIST_ITEM MiniListItem_t
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< 当 configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设为 1 时,设置为已知值,用于精简链表项数据完整性校验。*/
configLIST_VOLATILE TickType_t xItemValue; /*< 精简链表项的排序值,常设为最大值,使该链表项作为链表的末尾标记。*/
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*< 指向链表中的下一个 ListItem_t 类型链表项。*/
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< 指向链表中的上一个 ListItem_t 类型链表项。*/
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
struct xLIST
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< 当 configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设为 1 时,设置为已知值,用于链表数据完整性校验。*/
volatile UBaseType_t uxNumberOfItems; /*< 链表中 ListItem_t 类型链表项的数量。*/
ListItem_t * configLIST_VOLATILE pxIndex; /*< 用于遍历链表的索引指针,指向 listGET_OWNER_OF_NEXT_ENTRY 调用返回的最后一个项。*/
MiniListItem_t xListEnd; /*< 链表的末尾标记链表项,其 xItemValue 为最大值,始终位于链表末尾。*/
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< 当 configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设为 1 时,设置为已知值,辅助链表数据完整性校验。*/
} List_t;
2.核心操作函数
2.1 vListInitialise
vListInitialise 是 FreeRTOS 中用于初始化链表(List_t 结构体)的核心函数,其作用是将一个链表设置为初始状态,为后续添加节点做好准备。
void vListInitialise( List_t * const pxList )
{
// 初始化遍历指针:让链表的索引指针先指向末尾哨兵节点
// (后续遍历会从这里开始移动)
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );
// 给末尾哨兵节点设置最大排序值
// 因为链表按值从大到小排列,这样它就永远在链表最后
pxList->xListEnd.xItemValue = portMAX_DELAY;
// 让哨兵节点的前后指针都指向自己
// 这样链表为空时,前后指针形成自循环(方便判断空状态)
pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );
pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );
// 初始时链表没有任何业务节点,所以计数为0
pxList->uxNumberOfItems = 0U;
// 如果开启了链表完整性校验,就写入特征值
// (用于后续检测内存是否被异常修改)
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
初始化完成后,链表处于 "空链表" 状态,其内部结构如下:
- 哨兵节点
xListEnd形成自循环(前后指针都指向自己) - 遍历索引
pxIndex指向哨兵节点 - 节点计数器
uxNumberOfItems为 0 - 哨兵节点的排序值为最大值,确保它始终在链表末尾
2.2 vListInitialiseItem
这个函数用于初始化一个 ListIte 类型的链表节点(业务节点),让它处于 “可被添加到链表” 的状态,主要做了两件事:
剩余60%内容,订阅专栏后可继续查看/也可单篇购买
嵌入式面试八股文全集 文章被收录于专栏
这是一个全面的嵌入式面试专栏。主要内容将包括:操作系统(进程管理、内存管理、文件系统等)、嵌入式系统(启动流程、驱动开发、中断管理等)、网络通信(TCP/IP协议栈、Socket编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。
查看19道真题和解析