FreeRTOS通用链表解析

1.核心结构体

List_t 是链表本身,管理链表。

ListItem_t 是“正常节点”,用来挂载任务等对象。

MiniListItem_t 是“精简节点”,专门当链表的“哨兵/结束标记”。

ListItem_t

普通节点

xItemValue, pxNext, pxPrevious, pvOwner, pvContainer

真正存储任务/对象的节点

MiniListItem_t

精简节点

xItemValue, pxNext, pxPrevious

链表头尾的哨兵节点

List_t

容器

uxNumberOfItems, pxIndex, xListEnd

管理整个链表,带有结束标记

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编程等)、开发工具(交叉编译、调试工具等)以及实际项目经验分享。专栏将采用理论结合实践的方式,每个知识点都会附带相关的面试真题和答案解析。

全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务