RTOS之任务调度

一、就绪列表的结构

就绪列表是一个数组,数组元素的数量和最大支持的优先级数量一致。若最大任务优先级设置为 56 ,就绪列表会是一个包含 56 个元素的数组,同时会存在 56 个就绪链表。数组里每个元素存放的是对应优先级下的任务控制块的指针。

#define configMAX_PRIORITIES 56

// 就绪列表数组,每个元素是一个任务控制块指针
TaskHandle_t *pxReadyTasksLists[ configMAX_PRIORITIES ];
任务控制块里与链表相关的成员,可用于把任务连接到链表之中。
ListItem_t            xStateListItem;
ListItem_t            xEventListItem;

// 将任务的 xStateListItem 插入到就绪任务列表中
vListInsert(&readyTaskList, &task1.xStateListItem);

xStateListItem作用是将任务连接到状态列表,借助这个列表项能够明确任务所处的状态,例如就绪、阻塞、挂起等。不同状态的任务会被组织成不同的链表,而 xStateListItem 可让任务成为这些链表中的一个节点。

xEventListItem:作用是将任务连接到事件列表。当任务等待某个事件(像信号量、消息队列等)时,就会通过 xEventListItem 被添加到对应的事件等待链表中。

二、任务调用逻辑

在 FreeRTOS 中任务的执行主要取决于 pxCurrentTCB 指向哪个任务。

1. 确定最高优先级的就绪任务链表

在调度器进行任务选择时,首先会找出所有就绪任务中的最高优先级,这个最高优先级存储在 uxTopReadyPriority 变量中。然后通过 pxReadyTasksLists[uxTopReadyPriority] 找到对应最高优先级的就绪任务链表。

2. 同等优先级任务的轮换

  • 时间片检查:系统时钟节拍中断会周期性触发,在中断处理函数中会检查当前正在执行的任务的时间片是否用完。如果时间片用完,就会触发任务切换。
  • 选择下一个任务:每个任务控制块(TCB)中包含一个 xStateListItem 链表节点,通过该节点可以将任务连接到就绪链表中。当需要进行任务切换时,调度器会从当前任务所在的链表中找到下一个任务。通常是从当前任务的 xStateListItem 开始,通过其 pxNext 指针找到链表中的下一个任务节点。
  • 更新 pxCurrentTCB:找到下一个要执行的任务后,将 pxCurrentTCB 赋值为该任务的 TCB 指针。pxCurrentTCB 是一个指向当前正在执行任务的 TCB 的指针,更新它意味着将控制权切换到新的任务
 TCB_t *pxNextTCB = ( TCB_t * ) listGET_LIST_ITEM_OWNER( pxNextListItem );

3. 任务执行

  • 保存当前任务的上下文:把当前任务的寄存器值(如通用寄存器、程序计数器等)保存到该任务的栈中,并更新当前任务的栈指针。
  • 恢复新任务的上下文:从 pxCurrentTCB 指向的新任务的栈中恢复寄存器值,同时更新处理器的栈指针为新任务的栈指针。
  • 跳转到新任务的代码执行:将程序计数器设置为新任务的入口地址,新任务开始执行。

三、链表

1.List_t (链表)

用于管理链表,为任务调度、事件管理等功能提供了基础。管理了就绪任务列表,阻塞任务列表,事件等待列表。

//List_t 结构体及成员作用
typedef struct xLIST
{
    UBaseType_t uxNumberOfItems;  // 链表中节点的数量
    ListItem_t *pxIndex;          // 当前索引指向的节点
    MiniListItem_t xListEnd;      // 链表的结束标记节点
} List_t;

2. ListItem_t (链表项)

链表项是构成链表节点的基础,主要用于将任务控制块(TCB)或者其他需要管理的对象连接到链表中,以实现对任务、事件等的高效管理和调度。

//ListItem_t 结构体及成员作用
typedef struct xLIST_ITEM
{
    // 用于将节点插入到链表中的指针
    struct xLIST_ITEM * pxNext;
    struct xLIST_ITEM * pxPrevious;
    // 指向包含该节点的列表的指针
    List_t * pxContainer;
    // 用于排序或比较的数值,通常与任务的优先级等相关
    TickType_t xItemValue;
} ListItem_t;

vListInsert 是 FreeRTOS 提供的一个函数,用于将一个链表项(ListItem_t)插入到指定的链表(List_t)中。通过调用 vListInsert 函数,将任务的 xStateListItem 插入到对应优先级的就绪任务链表中,从而实现将任务添加到相应链表的目的。

// 定义就绪任务链表数组,每个数组元素代表着一个链表
List_t pxReadyTasksLists[ configMAX_PRIORITIES ];

// 初始化就绪任务链表,轮询初始化所有优先级链表
void vInitialiseReadyTaskLists( void )
{
    UBaseType_t uxPriority;

    for( uxPriority = ( UBaseType_t ) 0U; uxPriority < ( UBaseType_t ) configMAX_PRIORITIES; uxPriority++ )
    {
        vListInitialise( &( pxReadyTasksLists[ uxPriority ] ) );//初始化链表
    }
}

// 将任务添加到就绪任务链表
void vAddTaskToReadyList( TaskHandle_t pxTask )
{
    UBaseType_t uxPriority = pxTask->uxPriority;
    vListInsert( &( pxReadyTasksLists[ uxPriority ] ), &( pxTask->xStateListItem ) );
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值