• 基于STM32结合CubeMX学习Free-RT-OS的源码之任务调度


    目录

     任务调度

    任务的三种状态

    在抢占式的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 ); 则会在下一次调度时被切换。

  • 相关阅读:
    百度地图开发入门(6):3D建筑
    【Python】Python爬虫使用代理IP的实现
    MATLAB切片
    {大厂漏洞 } OA产品存在SQL注入
    【01】区块链技术概述
    OC iPhoneX UIScrollView顶部有空白问题
    MATLAB初步进行机器学习
    Java高级——Class文件及解析
    什么是美颜SDK?美颜SDK对比评测
    JVM
  • 原文地址:https://blog.csdn.net/PHILICS7/article/details/127830696