列表和列表项

FreeRTOS中使用 双向循环链表 表示列表 用来跟踪任务

一个任务有两个 列表项(事件列表项、状态列表项),列表项通过指针指向任务的TCB,当任务的状态列表项挂在在哪个列表中(就绪、阻塞、挂起)这个任务就处于那种状态

  • 事件列表项
    • 任务在等什么
    • 队列、信号量、互斥量、事件组、流缓冲区和消息缓冲区的等待列表 和 直接任务通知的等待
    • 有相应事件触发后,内核去对应事件的等待列表中查找哪个任务在等待该事件,不需要便利所有阻塞的任务
  • 状态列表项
    • 任务什么时候能运行
    • 就绪、阻塞、挂起列表,这些列表在全局中定义好的,任务创建时加入某一个列表

在这里插入图片描述

列表项
typedef struct xLIST_ITEM 			ListItem_t;  
typedef struct xMINI_LIST_ITEM 	 	 MiniListItem_t;

typedef struct xLIST
{
    listFIRST_LIST_INTEGRITY_CHECK_VALUE      //校验值
    volatile UBaseType_t uxNumberOfItems;	  //列表中列表项个数
    ListItem_t * configLIST_VOLATILE pxIndex; //用于遍历列表的指针           
    MiniListItem_t xListEnd;                  //末尾列表项		//循环列表,找到末尾 +1即使列表头
    listSECOND_LIST_INTEGRITY_CHECK_VALUE     //校验值
} List_t;

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;
};  //用于标记列表末尾 和 挂在其他插入列表中的 列表项


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;                                      //列表项的拥有者,指向该任务的PTB
    struct xLIST * configLIST_VOLATILE pxContainer;      //列表项所在列表,阻塞、就绪、挂起
    listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE        	//校验值
};
列表API
  • void vListInitialise( List_t * const pxList )
    • 初始化列表
  • void vListInitialiseItem( ListItem_t * const pxItem )
    • 初始化列表项
  • void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
    • 列表升序插入列表项
  • void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
    • 列表末尾插入列表项,插到列表pxIndex指针所指列表项前面
  • unsigned long uxListRemove( ListItem_t * const pxItemToRemove )
    • 列表移除列表项
    • 返回 列表剩余列表项数量

就绪列表

一个由 List_t 类型的变量组成的数组,数组大小为 configMAX_PRIORITIES

PRIVILEGED_DATA static List_t pxReadyTasksLists[ configMAX_PRIORITIES ];

数组的每个索引,对应一个优先级,调度器需要寻找下一个要运行的任务时,它会 从最高优先级向最低优先级扫描这个数组,找到第一个非空的就绪列表,然后取出该列表头部的任务来运行。

阻塞列表

通常是两个有序的(升序)链表。

  • xDelayedTaskList1
  • xDelayedTaskList2
  • pxDelayedTaskListpxOverflowDelayedTaskList 这两个指针会指向上面两个列表,用于处理系统滴答计数器溢出的情况。

唤醒时间(Unblock Time) 排序。任务的 xWakeTime 值(即它应该被唤醒的时刻)被用作排序的关键字。

作用:

  • 当一个任务调用 vTaskDelay() 或等待一个带有超时时间的事件(如 xQueueReceive(..., timeout))时,它会被从就绪列表中移除,并按其唤醒时间插入到阻塞列表中。塞入列表时会判断延时时间,决定塞入溢出前列表还是溢出后列表
  • 每次 系统时钟滴答中断(Tick Interrupt) 发生时,中断服务程序都会检查阻塞列表的头项。如果某个任务的唤醒时间小于或等于当前时间,说明它应该被唤醒了,就会将其从阻塞列表移回就绪列表。

挂起列表

挂起是一种 由开发者主动发起 的任务状态,与等待事件无关

数据结构:一个简单的 List_txSuspendedTaskList

组织方式:无序。所有被挂起的任务都放在这个列表里。

作用

  • 当一个任务调用 vTaskSuspend() 时,无论它当前在什么状态(就绪、阻塞等),都会被强制移出原来的列表,并加入到挂起列表中。
  • 被挂起的任务 永远不会被调度器选择运行,直到其他任务或中断调用 vTaskResume() 将其恢复。恢复时,任务会根据其情况被放回就绪列表或阻塞列表。
  • vTaskSuspendAll() 是一个不同的概念,它挂起的是调度器本身,而不是单个任务。
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐