基于STM32结合CubeMX学习Free-RT-OS的源码之任务调度
目录
在抢占式的FREE RT OS中,调度器如何选择它需要执行的任务?
xTaskIncreamentTick(void) tick中断的回调函数。
任务调度
目前实时操作系统(RTOS)多数为抢占式的系统。
#define configUSE_PREEMPTION 1
Free RT OS使用抢占式的任务调度,高优先级的任务抢占低优先级的任务执行。
Free rt os 会根据创建任务的优先级建立多个优先级就绪链表。再创建两个个阻塞链表,一个挂起链表。
就绪链表数组。
阻塞链表
PRIVILEGED_DATA static List_t xDelayedTaskList1 = {0}; //延时的任务
PRIVILEGED_DATA static List_t xDelayedTaskList2 = {0}; 用于超出当前tick计数的延迟。
挂起链表
任务的三种状态
- 就绪:等待调度就能得到执行。
- 阻塞:等待某个条件,常见的有系统延时等待滴答数。
- 挂起:必须要手动进行唤醒。
默认是0-31个优先级,优先级数字越大则优先级等级越高(这与中断嵌套的优先级数字越大则优先级越小)相反。
创建任务后,该任务会根据优先级放在不同的就就绪链表中。
任务可以主动阻塞。在阻塞后,该任务的会从就绪列表中移除并放入阻塞列表中,比如常见的阻塞API函数 OS_Delay(),它会等待tick中断唤醒。唤醒后再次加入它所在优先级的链表中。
在抢占式的FREE RT OS中,调度器如何选择它需要执行的任务?
从高优先级的任务链表中向链表的尾部遍历,若该高优先级链表没有就绪状态的任务,则向下,向低优先级的链表遍历。
----------------------------------------> 高优先级链表(同一优先级的任务)先向尾部遍历。
| (再向下遍历)
|
|
|
|
|
v
在同等优先级的情况下,若该任务的优先级大于0则后创建的任务会先执行。
创建任务的顺序 :任务1->任务2->任务3
执行顺序 :任务3->任务1->任务2
若该优先级的任务和空闲任务IDLE的优先级相同(也就是为0),则按创建任务的顺序执行。
( 创建任务的顺序和执行任务的顺序相同) 空闲任务(IDLE空闲任务会主动礼让给其他任务)->任务1->任务2->任务3 。(每个任务执行完毕则又插到链表尾部如此往复)。
见源码
什么时候会产生任务的调度?
- tick中断(这个在free rt os中默认是以systick为滴答时基)。(下文记录这个tick中断回调函数)
- 主动调用taskYIELD()进行任务切换。
- 硬件中断,这个有很多种,比如在串口中断回调函数中,或者是其他的中断回调函数中唤醒了某个高线程,则在中断结束后立刻发生调度,无需等待tick中断的调度。
什么时候高优先级的任务进行抢占?
- 高优先级的任务为就绪状态的情况下, tick中断产生调度任务进行切换(当前任务压入自己的任务栈,PSP指针指向新任务的函数入口)PSP是进程堆栈指针。(这也是绝大多数情况)
- 硬件中断产生唤醒高优先级的任务。(在 RTOS里最低优先级的硬件中断也高于最高优先级的任务,硬件中断唤醒了某个高优先级的任务,则离开进行抢占)
不抢占,不礼让的Free RT OS会发生什么?
如果通过宏配置不抢占也不礼让,无论是否是同优先级,那么永远只有当前任务能一直执行。
xTaskIncreamentTick(void) tick中断的回调函数。
/* Called by the portable layer each time a tick interrupt occurs.
Increments the tick then checks to see if the new tick value will cause any
tasks to be unblocked. */
翻译:
每次tick中断发生时由移植层调用。增加tick值,然后检查新的tick值是否会引起任何变化要解除阻塞的任务。
在xTaskIncreamentTick(void)中
只有配置了可抢占才会发生任务的调度。
在所有任务的优先级相同时,只有配置了可抢占,且配置了使用同优先级下采用时间片轮转的方法,才会使各个任务交替轮流执行一段时间。
常用的在硬件嵌套中断的回调函数中唤醒任务。
比如释放一个信号量
static portBASE_TYPE xHigherPriorityTaskWoken; //发送信号量后切换任务的标记
在中断嵌套中调用
xSemaphoreGiveFromISR(myBinarySem01Handle,&xHigherPriorityTaskWoken);
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
通过查看xHigherPriorityTaskWoken的值来判断是否立刻进行任务切换。(PdTRUE立刻切换,否则不切换)
如果最后不调用 portYIELD_FROM_ISR( xHigherPriorityTaskWoken ); 则会在下一次调度时被切换。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?