freeRTOS小结——任务管理
概述
freeRTOS中推荐TASK运行流程如下图所示,TASK无限循环于接收消息和处理消息的过程中。
实际上这也是大部分嵌入式系统中,TASK都采用这样的运行流程。这样的设计,非常适合将软件模块移植到到TASK中:消息即对应软件模块对外提供的功能接口,TASK即不停的监听接口并进行相应处理。
当然freeRTOS也支持TASK在执行完成指定处理后,注销自己,
实际上,这也是某些OS将TASK细分为process和thread的原因:process不会注销自己,thread会。
TASK状态
freeRTOS中将TASK的状态粗分为运行态(running)和非运行态(notrunning),前者表示该TASK的指令集合正在被CPU执行,后者表示TASK的指令集合没有被CPU执行。
非运行态可以细分为挂起态(suspend)、锁定态(blocked)和就绪态(ready)
其中
· 就绪态,表示TASK准备就绪,等待转入运行态,是否转入运行态由freeRTOS的调度策略确定。
· 挂起态,表示TASK被其他TASK或自己挂起(调用API函数vTaskSuspend()),只能由用户主动解除挂起(调用函数vTaskResume()),才能退出挂起态,转入就绪态。
· 锁定态,表示TASK处于等待某一事件(Event)的状态,只有等待的事件到来,TASK才能推出锁定态,转入就绪态。
· TASK可由其他任一状态转入挂起态,由运行态转入时,即为被自己主动挂起;K由锁定态或就绪态转入时,即为被其他TASK挂起。
· TASK只可由运行态转入锁定态,此时为TASK为等待某一事件(Event)而主动放弃在CPU上执行。
· TASK在创建后,自动进入就绪态。
TASK基本操作
freeRTOS中提供以下基本的任务相关操作,
· 创建/删除任务
· 获取/设置任务优先级
· 锁定任务
任务调度策略
任务调度策略,即从处于就绪态的TASK集合中选择出在CPU上执行的TASK的策略。
freeRTOS推荐使用基于时间片(timeslice)机制的抢占(preemption)策略,如下图所示,
· 所有处于就绪态的TASK按照优先级分为N个队列,每次选择最高优先级队列中处于队首的TASK到CPU上执行。
· 若选择的TASK与之前执行的TASK不一致,即为任务切换,之前执行的TASK将会重排到所在队列的队尾,其他细节将在后边讲到。
· OS初始启动时,任务调度过程会被触发。
· TASK为等待某一事件(Event),由运行态转入锁定态时,任务调度会被触发。
· TASK被自己主动挂起,由运行态转入挂起态时,任务调度会被触发
· 时间片到期时,任务调度会被触发,时间片的概念将在后边详述。
· 接收到中断时,对应的中断处理程序可能触发任务调度。
任务切换
任务切换过程与CPU处理中断过程十分类似,也需要压栈和出栈操作来保存寄存器数据。但有所不同,每一个任务都有自己的栈,用于切换时保存或恢复其在CPU上运行时的寄存器数据。
如下图所示,任务切换中的当前任务记为CURR_TASK,下一任务记为NEXT_TASK,
OS往往在压栈后才选择最高优先级的TASK(freeRTOS提供API函数vTaskSwitchContextConst()),因此切换之前,OS并不能明确CURR_TASK是否就是NEXT_TASK,因此CURR_TASK需要将寄存器数据保存到自己专属的栈内,以便后续任务切换中成为NEXT_TASK时,能够恢复寄存器数据。
同理,NEXT_TASK在任务切换时也需要从自己专属的栈内取出数据恢复寄存器。
其中freeRTOS提供全局变量pxCurrentTCB记录CURR_TASK的栈地址。
任务切换过程如下图所示,
由于任务切换过程在OS中运行十分频繁,且和硬件联系十分紧密,它往往使用汇编语言编写。
TASK的专属栈从heap中分配而来,栈的大小需要根据TASK内函数调用的深度来确定。
时间片机制
时间片机制是指OS每隔一段时间都对自身基本状态进行检查,并触发一次任务调度。这一段时间即为时间片,也被记为tick。
其设计初衷有二:一是避免低优先TASK不主动挂起和锁定导致高优先级TASK无法在CPU上运行;二是向OS和TASK提供时间信息。
时间片机制往往基于中断机制实现,具体细节将在后边提到。时间片机制会导致OS周期性地尝试TASK切换,如下图所示
其中,
· t1~t2时间段,TASK 1在CPU上执行
· t2时刻,时间片超时,OS发现存在更高优先级的TASK2,因此触发TASK切换,切换到TASK 2
· t2~t3时间段,TASK 2在CPU上执行
· t3时刻,时间片超时,OS发现没有更高优先级的TASK,不触发TASK切换
基于时间片机制,OS除可周期触发任务调度外,还可以向OS和TASK提供时间信息——OS中所有与时间相关的功能,如后边将会提到的TIMER TASK,以及接收事件时的等待时间,都是基于时间片机制来实现的。
需要注意,时间片机制是可以关闭的。
后台任务
freeRTOS提供若干默认任务,用于维护OS状态和向用户提供更多功能,包括
· IDLE TASK
· TIMER TASK
IDLE TASK
freeRTOS会在OS启动时默认创建一个名为IDLE的任务,其优先级最低,主要是在其他任务都不需要占用CPU时运行,用于统计和维护OS的状态信息,如CPU空闲率。
freeRTOS也提供用户可自定义的钩子函数(HOOK function,vApplicationIdleHook)在IDLE任务中运行。
实际上,大部分的RTOS都会默认创建一个IDLE任务,用于CPU空闲时运行。
TIMER TASK
freeRTOS提供一个名为Timer的可选任务,在OS启动时创建,优先级最高,其主要是向用户任务提供逻辑定时器功能,适用于定时器时间要求并不十分严格的用户任务。
理论上,其可提供的定时器数量可以无限多。