微型操作系统内核源码详解系列四(3):操作系统调度算法(FreeRTOS内核篇上)

系列一:微型操作系统内核源码详解系列一:rtos内核源码概论篇(以freertos为例)-CSDN博客

系列二:微型操作系统内核源码详解系列二:数据结构和对象篇(以freertos为例)-CSDN博客

系列三:微型操作系统内核源码详解系列三(0):空间存储及内存管理篇(前置篇)-CSDN博客

                微型操作系统内核源码详解系列三(1):任务及切换篇(任务函数定义)-CSDN博客

                微型操作系统内核源码详解系列三(2):任务及切换篇(任务函数定义)-CSDN博客

                微型操作系统内核源码详解系列三(3):任务及切换篇(任务函数定义)-CSDN博客

                微型操作系统内核源码详解系列三(4):arm架构篇-CSDN博客

                微型操作系统内核源码详解系列三(5):进程与线程-CSDN博客

系列四:

 ​​​​​微型操作系统内核源码详解系列四(1):操作系统调度算法(linux0.11版本内核)-CSDN博客

微型操作系统内核源码详解系列四(2):操作系统调度算法(rt-thread内核)-CSDN博客

微型操作系统内核源码详解系列四(3):操作系统调度算法(FreeRTOS内核篇上)-CSDN博客

微型操作系统内核源码详解系列四(4):操作系统调度算法(FreeRTOS内核篇下)-CSDN博客

系列五:

微型操作系统内核源码详解系列五(1):arm cortex m3架构-CSDN博客

微型操作系统内核源码详解系列五(2):cm3下栈的初始化-CSDN博客

微型操作系统内核源码详解系列五(3):cm3下调度的开启-CSDN博客

微型操作系统内核源码详解系列五(四):cm3下svc启动任务-CSDN博客

微型操作系统内核源码详解系列五(五):cm3下Pendsv切换任务上篇-CSDN博客

微型操作系统内核源码详解系列五(六):Pendsv切换任务下篇-CSDN博客

在经过前几篇文章的讲解,相信读者对调度器有了一定的了解。

现在让我们进入对FreeRTOS调度算法的讲解,如果读者真正能理解FreeRTOS内核的本质就是一个调度器的话,其实已经差不多掌握这个实时操作系统了。

笔者在这一章将会简单介绍FreeRTOS内核选择策略的函数,即它是如何根据优先级进行选择的,在进行选择之后它又是如何进入到任务切换函数的。在讲解完这一章后,笔者将会回到对FreeRTOS内核源码的讲解。其实截至到目前为止,笔者只是简单介绍了链表函数、入口函数、内存管理函数的源码,博客主要是以操作系统的基础知识为主,但这其实是笔者认为最重要的东西。否则,读者对RTOS的理解层面可能只停留在c语言层面,甚至可能一头扎进函数调用关系这片茫茫大海中;容笔者说一下个人看法,从c语言和数据结构算法的层面学习,只能说是舍本逐末,透过Freertos这个小型系统,窥见庞大的操作系统架构的一角,这才是我们学习的重点。

现在让笔者讲一讲FreeRTOS内核的是如何选择优先级任务的,

让我们看看tasks.c文件中的这几行代码:

configUSE_PORT_OPTIMISED_TASK_SELECTION这个宏是定义查找任务的方法,0表示通用方法,1表示根据处理器架构优化后的方法。

讲到taskRECORD_READY_PRIORITY,那就该回收我系列3(3)的讲解了:

参考prvAddNewTaskToReadyList函数源码,prvAddTaskToReadyList函数在每个任务在添加到就绪列表时都会执行,然后taskRECORD_READY_PRIORITY就在这个函数中,如上图所示,它会与uxTopReadyPriority(默认是0)进行比较,然后uxTopReadyPriority记录两者中的较大者,不断的对每一个新添加进来的任务优先级进行比较,这其实就是在找出最大的优先级,而不必死板的按照我们在configMAX_PRIORITIES定义的最大优先级设定,至于为什么这么干,读者看到后面的代码便知(为了减少遍历时间)。

顺便一提,FreeRTOS中的任务优先级跟我们在mcu中学习到的中断优先级判断是不一样的,也跟RTT和uc/os不一样,mcu中的中断优先级是数字越小,优先级越大,RTT和uc/os的任务优先级也是这样;FreeRTOS中是任务优先级的数字越大,优先级越大。

taskSELECT_HIGHEST_PRIORITY_TASK就是通用的选择算法的具体函数了,先对uxTopReadyPriority的值进行保存;每一个优先级都有一个特定的链表,while判断就绪链表的这个优先级是否有任务挂载在上面,如果没有,就继续找下一个优先级的链表,(configASSERT笔者之前提过,是断言,用来debug,如果uxTopPriority小于0,会触发它);--uxTopPriority,被设定为是代表最大优先级的数字,自减操作代表从就绪列表最后一个链表(优先级最高的链表)开始查找,直到找到任务链表不为空的优先级任务,那么这个任务肯定也是所有任务中优先级最大的任务,然后获取这个任务的TCB并更新pxCurrentTCB(切换的具体函数),最后更新uxTopReadyPriority的值。

可能有读者会有疑问,为什么要更新uxTopReadyPriority的值?更新它不代表轮询会到比这个优先级更低的优先级吗?那这不成一次性的吗?

由于笔者还没讲空闲任务和优先级那些,让笔者简短介绍一下:

读者回忆一下笔者在arm架构篇的内容,笔者将在这里介绍它的原理,

在FreeRTOS中,最高优先级且只有一个的任务只有通过延时,其他任务才可以被执行,当它延时的时候,它会被踢出就绪列表,只有时间一到,它才会被加入到就绪列表,这个时候uxTopReadyPriority的值会被更新,这时会从高优先级的依次向低优先级遍历。同理,当最高优先级因为延时被移除,次高优先级就变成了最高优先级,其他优先级又只能等这个最高优先级的任务进入延时,这时它们才会被执行,也就是说,如果你的优先级设置得不好,延时设置的也不好,那么优先级比较低的任务,永远不会被执行。

笔者上面介绍了通用方法,下面介绍另一种根据arm架构优化的方法,笔者个人认为,这种方法其实是远好于RTT空间换时间的算法的,当然,RTT内核也采用了这种方法,开发者可以自己选择。

另一种方法就是通过arm架构的_clz指令,其实也是利用图表法,笔者将会在下一章讲解。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值