FreeRTOS任务调度主要变量

之前介绍的和FreeRTOS任务调度相关的数据结构即内存分配实现。xLIST、heap_4、TCB结构体。任务调度就是基于这些结构体实现。这次介绍调度相关的主要变量。

代码在FreeRTOSMini.c文件签名部分。

//当前的任务序号,生成任务唯一号
PRIVILEGED_DATA static volatile UBaseType_t uxCurrentNumberOfTasks = (UBaseType_t)0U;

//当前执行任务的tcb
PRIVILEGED_DATA TCB_t* volatile pxCurrentTCB = NULL;

//就绪任务列表
//定义优先级个数的就绪任务列表数组。每个优先级可以维持一个任务List
PRIVILEGED_DATA static List_t pxReadyTasksLists[configMAX_PRIORITIES];

//两个延迟列表轮流着用,系统tick溢出了就调换延迟列表
//用两个延迟列表来解决延迟定时器溢出问题。如果延迟计算后的tick小于当前系统tick,那么就延时到溢出了,这时候延时任务就加入延迟溢出列表
//延迟任务列表1
PRIVILEGED_DATA static List_t xDelayedTaskList1;                         
//延迟任务列表2
PRIVILEGED_DATA static List_t xDelayedTaskList2;                         
//延迟任务列表的指针
PRIVILEGED_DATA static List_t* volatile pxDelayedTaskList;              
//延迟超时任务列表的指针
PRIVILEGED_DATA static List_t* volatile pxOverflowDelayedTaskList;      
//调度程序挂起时已准备好的任务,当调度器恢复时,它们将被移动到就绪列表中。
PRIVILEGED_DATA static List_t xPendingReadyList;

//系统节拍计数
PRIVILEGED_DATA static volatile TickType_t xTickCount = (TickType_t)0;

//下一个出块时间
//在调度程序启动之前初始化为 portMAX_DELAY。
PRIVILEGED_DATA static volatile TickType_t xNextTaskUnblockTime = (TickType_t)0U;

//任务是否被挂起
PRIVILEGED_DATA static volatile UBaseType_t uxSchedulerSuspended = (UBaseType_t)pdFALSE;

//调度器是否挂起
PRIVILEGED_DATA static volatile BaseType_t xSchedulerRunning = pdFALSE;

//是否要执行上下文切换
PRIVILEGED_DATA static volatile BaseType_t xYieldPending = pdFALSE;

//延迟的节拍数
PRIVILEGED_DATA static volatile TickType_t xPendedTicks = (TickType_t)0U;

//系统任务数
PRIVILEGED_DATA static UBaseType_t uxTaskNumber = (UBaseType_t)0U;

//溢出的节拍次数
PRIVILEGED_DATA static volatile BaseType_t xNumOfOverflows = (BaseType_t)0;

//空闲任务句柄
PRIVILEGED_DATA static TaskHandle_t xIdleTaskHandle = NULL;

//最高的就行任务的优先级
PRIVILEGED_DATA static volatile UBaseType_t uxTopReadyPriority = tskIDLE_PRIORITY;

//最高的任务优先级
const volatile UBaseType_t uxTopUsedPriority = configMAX_PRIORITIES - 1U;

uxCurrentNumberOfTasks是无符号long类型,每创建一个任务就把该私有变量加1,把这个数字设置到创建的任务的TCB里,作为任务唯一号,该变量就是记录唯一号增加的用处。

pxCurrentTCB很重要,该变量存当前运行的任务的TCB,调度任务就是在systick中断判断是否需要换任务运行。如果需要切换任务,那么触发PendSV中断。在PendSV中断函数里先按pxCurrentTCB的栈顶指针压栈保存上下文,然后调用切换任务逻辑,切换任务逻辑按优先级找到要运行的TCB设置到pxCurrentTCB。然后按pxCurrentTCB出栈寄存器值恢复pxCurrentTCB指向的新TCB的上下文,退出PendSV后按新上下文执行切换后的新任务。都是通过pxCurrentTCB变量。

pxReadyTasksLists是优先级个数的xLIST数组。该数组可以保存每个优先级的对应列表。创建任务时候就把创建的任务加入对应优先级位置的就绪列表上。优先级对应pxReadyTasksLists的数组索引,具体TCB的xStateListItem状态列表项挂接到对应位置列表中。调度时候也是按最高优先级往低优先级任务调度执行。相同优先级的任务轮流共享时间片。高优先级任务可以抢占低优先级任务时间片。

xDelayedTaskList1和xDelayedTaskList2用了存调用vTaskDelay进行延时的任务。按解除时间排序。为什么需要两个列表来存延迟任务。因为延时后的解块时间是按OS当前系统节拍xTickCount加上调用延迟函数延迟的节拍数(都是以系统节拍数为参考),既然系统节拍数是个整数,那么总有溢出的时候,溢出后又从0开始。如果一个任务调用延时函数延迟10个节拍。没溢出的情况下该任务解除延时节拍应该在xTickCount+10。如果xTickCount+10>xTickCount那么没溢出,该任务放入没溢出的延迟列表。如果xTickCount+10<xTickCount那么解块时候OS节拍溢出了。对于这些任务该方法溢出延迟列表。OS节拍执行到xTickCount=0时候对调xDelayedTaskList1和xDelayedTaskList2列表。这样就完美解决了溢出问题。pxDelayedTaskList和pxOverflowDelayedTaskList指针正好来回在xDelayedTaskList1和xDelayedTaskList2对调。

xPendingReadyList我目前还没使用。

xTickCount是系统节拍数,每次Systick中断都给该值加一。代表整个系统时钟节拍,延迟到期解除都依据系统节拍计数。

xNextTaskUnblockTime记录最近解除延时的系统节拍。有任务调用延时函数时候都计算更新该值。延迟列表变动时候就把下次最近出块时间算好,避免每次从整个延迟列表计算出块时间,减少性能开销用的。

uxSchedulerSuspended标志调度器是否被挂起。

xSchedulerRunning标志任务调度器是否在运行。

xYieldPending是否要执行上下文切换。在程序中主动设置该变量让OS任务调度进行任务切换。其他切换是按时间片和任务优先级切换。该变量进行主动切换。

uxTaskNumber记录系统的任务数量。

xNumOfOverflows记录溢出的节拍数,目前我还没用到。

xIdleTaskHandle空闲任务句柄,执行空闲任务的TCB。没有任务时候就调用该句柄。

uxTopReadyPriority记录运行最高任务优先级。把要运行的最高优先级记录在该变量。防止每次遍历整个就绪任务数组导致开销大。任务调度后及时更新该变量的值。

uxTopUsedPriority记录创建和使用的最高优先级任务。比该位置高的优先级数组就不需要检查了,减少调度开销。

这些就是任务调度要用到的主要变量,创建任务和调度任务都会用到这些变量。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小乌鱼

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值