【FreeRTOS#1】多任务处理任务调度器任务状态
一、多任务处理
内核是操作系统的核心组件。学过ARM架构的朋友们都很清楚,STM32微控制器中只有一个内核。例如,在F1系列架构中,Cortex-M3内核通过D-bus和Sys-bus直接访问总线矩阵,通过ICode访问Flash闪存,其中没有其他核心辅助这些过程,换句话说STM32是32位单核微控制器。
实时操作系统中的每个程序都是受其控制的任务,而能同时执行多个任务的操作系统叫做多任务操作系统。
多任务操作系统对我们的开发过程具有简化设计流程的意义:
(1)操作系统的多任务处理和任务间通信允许将复杂的应用程序分为一组更小更容易管理的任务
(2)通过程序分割,能够更容易测试,分解工作和复用代码
(3)免去了开发者复杂的时序排序,由系统负责进行
在嵌入式实时操作系统中,多任务是以并发的方式进行的。这里区别并行和并发。
在多核系统中,通过一个核心负责一个任务,核心之间各负责各自不干扰的方式实现同时处理多个任务的过程叫做并行。
上图为并行过程,每一个颜色对应的任务就是一个核心负责的。
在嵌入式系统中,在某种调度规则下使单核对多任务分时复用的过程是并发过程。有些纯软件领域的人也会称这个过程为 伪并发。为什么叫做伪并发?请看下图:
在并发全过程中,只能使用一个内核,这意味着我们只可以使用分时复用的方法分配多任务,一定不可能出现一个时间段tn-1到tn内,存在两个任务正在执行。
二、任务调度器
刚才讲了多任务的概念,那么我们的FreeRTOS是如何调度多任务的呢?
FreeRTOS系统中存在一个多任务调度器。
一般情况下,FreeRTOS默认使用抢占式调度,同等优先级时使用时间片轮询调度。
抢占式调度简单来说就是,当Pr0、Pr1、Pr2 三个任务都已准备完毕时,我们优先调度Pr0。再或者Pr2执行到一半时,Pr1突然准备好了,则Pr1进行抢占运行,以此类推。
时间片轮询调度就是,若TSK1,TSK2,TSK3同优先级,按照嵌入式程序中常说的轮询顺序,在一个规定的时间片Tc下按照轮询顺序进行调度。
接下来我们分析几个示意图来理解这两个模式,
上图中,最初TSK2和TSK3都尚未准备完毕,只能先运行优先级最低的TSK1。当TSK2准备完毕时,立即抢占TSK1,接着TSK3准备完毕以及抢占。接着,TSK3因为遇到了delay等阻塞类函数,进入了阻塞状态,把执行权交给TSK2,等TSK3恢复,再次抢占。
这就很像抢厕所的例子,某个公司卫生间只有一个马桶,而普工、经理、老板都在某一刻想上大号。普工先赶到卫生间,不知道是否释放完毕,经理就急着敲门让他出来,然后自己进去。
紧接着老板也赶了过来,让拉一半的经理出来,老板自己进去。老板发现自己好像有点便秘,决定先出去缓一缓再继续,经理就进去了......
接下来就是时间片轮询访问了,这里需要注意的是:一般情况下,每一个Tc触发一次SysTick中断,但如果程序提前结束,则提前跳入下一个Tc。
三、任务状态
FreeRTOS系统中有四种任务状态:
(1)运行态:指的就是任务在正常运行的状态(单核系统只能有一个任务处在运行态)
(2)就绪态: 已准备好运行,但被更高优先级任务抢占的任务状态
(3)阻塞态:遇到了Delay/外部事件,处于等待状态
(4)挂起态:调用了suspend函数,强制使任务进入暂停状态
四个状态的转换关系如下图所示,
根据上图需要明确一个规律,只有就绪态能直接转换为运行态,其他状态想要进入运行态,必须先转换为就绪态。
在FreeRTOS系统中,任务状态是以列表形式存储在内存中的,这些列表被我们称为任务状态列表。
其实,这里所说的列表也是以链表形式实现的。
1. 就绪列表 pxReadyTasksLists [x], x代表抢占优先级
2. 阻塞列表 pxDelayedTaskList
3. 挂起列表 pxSuspendedTaskList
在32位嵌入式系统中,存在一个32位的寄存器用于代表0-31的优先级。当某一位为1,则就绪列表对应元素就有任务存在,底层算法中用此寄存器加快我们的遍历速度。
下图拿挂起列表举例,
需要注意的是,当多个同优先级的任务进入进入就绪/暂态/阻塞时,列表中的一个结点需要存储多个任务。
调度器总是在就绪表中选高优先级的出列。