freeRTOS的任务抢占和时间片轮转

2023-05-16

实时操作系统的一个特点就是可以任务抢占,高优先级的任务可以抢占比自己优先级低的任务,如果新任务优先级和当前人任务优先级一样,且在使能了时间片的方式的话,二者以时间片的方式共享cpu,时间片的粒度为一个sys tick心跳间隔。freeRTOS也支持这个性能,如果使能抢占,需要打开如下宏:

#define configUSE_PREEMPTION 1

时间片方式共享cpu

#define configUSE_TIME_SLICING 1

有2个问题:

  • 系统如何知道有比当前任务优先级高任务在等待执行
  • 系统在何时检测切换到高优先级的任务上。

要解答上面2个问题,首先freeRTOS的系统心跳system tick定时中断,可以触发任务切换,先看system tick的ISR函数核心代码,这里也是freeRTOS的核心:

if( xConstTickCount >= xNextTaskUnblockTime )
    {
        for( ; ; )
        {
            /*延时等待的任务都在pxDelayedTaskList中,如果该list为空,说明没有任务要待转入readyList中,直接将xNextTaskUnblockTime设置为最大,
            下一个tick到来时,也就不会在判断了*/
            if( listLIST_IS_EMPTY( pxDelayedTaskList ) != pdFALSE ) /*/
            {
                /* The delayed list is empty.  Set xNextTaskUnblockTime
                 * to the maximum possible value so it is extremely
                 * unlikely that the
                 * if( xTickCount >= xNextTaskUnblockTime ) test will pass
                 * next time through. */
                xNextTaskUnblockTime = portMAX_DELAY; /*lint !e961 MISRA exception as the casts are only redundant for some ports. */
                break;
            } /*pxDelayedTaskList不为空,有任务在等待调度,这样任务有2种情况,一个是超时了,一个是还未超时*/
            else
            {
                /* The delayed list is not empty, get the value of the
                 * item at the head of the delayed list.  This is the time
                 * at which the task at the head of the delayed list must
                 * be removed from the Blocked state. */
                pxTCB = listGET_OWNER_OF_HEAD_ENTRY( pxDelayedTaskList ); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
                xItemValue = listGET_LIST_ITEM_VALUE( &( pxTCB->xStateListItem ) );
                /*等待的任务定时器时间未到,则直接更新下次超时时间,跳出本次循环*/
                if( xConstTickCount < xItemValue )
                {
                    /* It is not time to unblock this item yet, but the
                     * item value is the time at which the task at the head
                     * of the blocked list must be removed from the Blocked
                     * state -  so record the item value in                         * xNextTaskUnblockTime. */
                    xNextTaskUnblockTime = xItemValue;
                    break; /*lint !e9011 Code structure here is deemed easier to understand with multiple breaks. */
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
                /*任务的定时器已经到时,则需要将该任务放到readyList中*/
                /* It is time to remove the item from the Blocked state. */
                listREMOVE_ITEM( &( pxTCB->xStateListItem ) );
                /* Is the task waiting on an event also?  If so remove
                 * it from the event list. */
                if( listLIST_ITEM_CONTAINER( &( pxTCB->xEventListItem ) ) != NULL )
                {
                    listREMOVE_ITEM( &( pxTCB->xEventListItem ) );
                }
                else
                {
                    mtCOVERAGE_TEST_MARKER();
                }
                /* Place the unblocked task into the appropriate ready
                 * list. */
                prvAddTaskToReadyList( pxTCB );

                /* A task being unblocked cannot cause an immediate
                 * context switch if preemption is turned off. */
                #if ( configUSE_PREEMPTION == 1 )
                {
                    /* Preemption is on, but a context switch should
                     * only be performed if the unblocked task has a
                     * priority that is equal to or higher than the
                     * currently executing task. */
                     /*定义了抢占的话,如果到时的任务优先级大于等于当前任务的优先级,则置位xSwitchRequired,触发一次任务切换*/
                     if( pxTCB->uxPriority >= pxCurrentTCB->uxPriority )
                     {
                        xSwitchRequired = pdTRUE;
                    }
                    else
                    {
                        mtCOVERAGE_TEST_MARKER();
                    }
                }
                #endif /* configUSE_PREEMPTION */
            }
        }
    }
    /*走到这里,以下几种可能的情况
    1> pxDelayedTaskList为空
    2> pxDelayedTaskList不为空,但是任务的定时时间还没有到
    3> pxDelayedTaskList不为空,任务的定时时间已经到了,同时,把到时的任务也放入了readyList中
    如果定义了抢占和cpu时间片,如果readyList中的任务数大于1,则置位xSwitchRequired,触发一次任务切换。
     */
    /* Tasks of equal priority to the currently running task will share
     * processing time (time slice) if preemption is on, and the application
     * writer has not explicitly turned time slicing off. */
     /*如果定义了configUSE_TIME_SLICING,也只是置位xSwitchRequired为true,那么相同优先级的任务如何切换的呢?*/
    #if ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) )
    {
        if( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ pxCurrentTCB->uxPriority ] ) ) > ( UBaseType_t ) 1 )
        {
            xSwitchRequired = pdTRUE;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    #endif /* ( ( configUSE_PREEMPTION == 1 ) && ( configUSE_TIME_SLICING == 1 ) ) */
    /*开启了抢占的话,如果有task yield pending了也会触发一次任务切换*/
    #if ( configUSE_PREEMPTION == 1 )
    {
        if( xYieldPending != pdFALSE )
        {
            xSwitchRequired = pdTRUE;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
    }
    #endif /* configUSE_PREEMPTION */

system tick定时任务干了的事情有:

  • 判断是否有任务在等待执行
  • 任务超时处理
  • 任务的抢占
  • 时间片调度

不管任务超时与否,system tick到来后,都会判断是否需要抢占和时间片轮换。

关于时间片,相同优先级的任务如何切换的呢?system tick的ISR只是把任务放入readyList中,任务切换执行是在另外 一个函数中vTaskSwitchContext。

freeRTOS中system tick到来之后都会调用一次vTaskSwitchContext。

所以查看vTaskSwitchContext的代码,找出答案。

void vTaskSwitchContext( void )
{
    if( uxSchedulerSuspended != ( UBaseType_t ) pdFALSE )
    {
        ....
    }
    else
    {
        xYieldPending = pdFALSE;
        traceTASK_SWITCHED_OUT();

        #if ( configGENERATE_RUN_TIME_STATS == 1 )
            ......
        #endif /* configGENERATE_RUN_TIME_STATS */

        /* Check for stack overflow, if configured. */
        taskCHECK_FOR_STACK_OVERFLOW();


        /* Select a new task to run using either the generic C or port
         * optimised asm code. */
        taskSELECT_HIGHEST_PRIORITY_TASK(); /*lint !e9079 void * is used as this macro is used with timers and co-routines too.  Alignment is known to be fine as the type of the pointer stored and retrieved is the same. */
        traceTASK_SWITCHED_IN();
        ........
        ........
    }
}

核心代码为taskSELECT_HIGHEST_PRIORITY_TASK();它的实现在:

    #define taskSELECT_HIGHEST_PRIORITY_TASK()                                                  \
    {                                                                                           \
        UBaseType_t uxTopPriority;                                                              \
                                                                                                \
        /* Find the highest priority list that contains ready tasks. */                         \
        portGET_HIGHEST_PRIORITY( uxTopPriority, uxTopReadyPriority );                          \
        configASSERT( listCURRENT_LIST_LENGTH( &( pxReadyTasksLists[ uxTopPriority ] ) ) > 0 ); \
        listGET_OWNER_OF_NEXT_ENTRY( pxCurrentTCB, &( pxReadyTasksLists[ uxTopPriority ] ) );   \
    } /* taskSELECT_HIGHEST_PRIORITY_TASK() */

最后在这 listGET_OWNER_OF_NEXT_ENTRY()

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                           \
    {                                                                                          \
        List_t * const pxConstList = ( pxList );                                               \
        /* Increment the index to the next item and return the item, ensuring */               \
        /* we don't return the marker used at the end of the list.  */                         \
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                           \
        if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) \
        {                                                                                      \
            ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       \
        }                                                                                      \
        ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         \
    }

轮训当前优先级的链表,通过节点的pvOwer拿到TCB指针(具体任务的任务块入口)。

宏接口一进来就pxIndex指向了下一个节点,比如当前链表中有2个任务,那system tick到来之后,直接跳转到了下个节点,提取下个任务

( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;

如果同一优先级的任务只有2个而且没有其他任务抢占,在这样特定情况下,每到一个system tick,就会切换到另外一个任务,2个任务来回切换共享cpu,切换时间以system tick为基准。

结合项目中的pxReadyTasksLists数据结构如下:

pxReadyTasksLists是以优先级为索引的数组链表,同一优先级的任务挂在对应的链表上。

所有链表均是唤醒链表。

到这里就是整个任务切换的大致过程。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

freeRTOS的任务抢占和时间片轮转 的相关文章

  • FreeRTOS例程4-串口DMA收发不定长数据

    FreeRTOS例程4 串口DMA收发不定长数据 知乎 zhihu com
  • FreeRTOS快速上手

    FreeRTOS使用 一 源码下载和移植文件提取 1 1 源码下载 在网站https sourceforge net projects freertos 可以找到freertos最新的源码 1 2 移植文件提取 根据第一步 我们会得到一个f
  • 【FreeRTOS 信号量】互斥信号量

    互斥信号量与二值信号量类似 但是互斥信号量可以解决二值信号量出现的优先级翻转问题 解决办法就是优先级继承 普通互斥信号量创建及运行 参阅安富莱电子demo 互斥信号量句柄 static SemaphoreHandle t xMutex NU
  • FreeRTOS-内核控制函数

    FreeRTOS 内核控制函数 FreeRTOS中有一些内核函数 一般来说这些内核函数在应用层不会使用 但是内核控制函数是理解FreeRTOS中断的基础 接下来我们逐一分析这些内核函数 taskYIELD 该函数的作用是进行任务切换 这是一
  • 【FreeRTOS】多任务创建

    作者主页 凉开水白菜 作者简介 共同学习 互相监督 热于分享 多加讨论 一起进步 专栏资料 https pan baidu com s 1nc1rfyLiMyw6ZhxiZ1Cumg pwd free 点赞 收藏 再看 养成习惯 订阅的粉丝
  • FreeRTOS系列

    本文主要介绍如何在任务或中断中向队列发送消息或者从队列中接收消息 使用STM32CubeMX将FreeRTOS移植到工程中 创建两个任务以及两个消息队列 并开启两个中断 两个任务 Keyscan Task 读取按键的键值 并将键值发送到队列
  • 【FreeRTOS开发问题】FreeRTOS内存溢出

    FreeRTOS内存溢出 如下图所示 FreeRTOS编译完成后可以看到 系统提示无法分配内存到堆 Objects Template axf Error L6406E No space in execution regions with A
  • FreeRTOS系列

    1 RTOS简介 RTOS全称为 Real Time Operation System 即实时操作系统 RTOS强调的是实时性 又分为硬实时和软实时 硬实时要求在规定的时间内必须完成操作 不允许超时 而软实时里对处理过程超时的要求则没有很严
  • FreeRTOS打印任务对CPU的占有率

    1 配置RTOS 1 打开RTOS Config Parameter 找到Run Time And Task States gathering related definitions 使能GENERATE RUN TIME STATS US
  • FreeRTOS+CubeMX系列第一篇——初识FreeRTOS

    文章目录 一 关于FreeRTOS 二 FreeRTOS的特点 三 如何在CubeMX上配置FreeRTOS 四 FreeRTOS文档资料 五 同系列博客 一 关于FreeRTOS 1 什么是FreeRTOS FreeRTOS是一个迷你的实
  • FreeRTOS临界区

    FreeRTOS临界区是指那些必须完整运行 不能被打断的代码段 比如有的外设的初始化需要严格的时序 初始化过程中不能被打断 FreeRTOS 在进入临界区代码的时候需要关闭中断 当处理完临界区代码以后再打开中断 FreeRTOS 系统本身就
  • freeRTOS使用uxTaskGetStackHighWaterMark函数查看任务堆栈空间的使用情况

    摘要 每个任务都有自己的堆栈 堆栈的总大小在创建任务的时候就确定了 此函数用于检查任务从创建好到现在的历史剩余最小值 这个值越小说明任务堆栈溢出的可能性就越大 FreeRTOS 把这个历史剩余最小值叫做 高水位线 此函数相对来说会多耗费一点
  • 基于HAL库的FREERTOS-----------三.队列

    一 队列简介 在实际的应用中 常常会遇到一个任务或者中断服务需要和另外一个任务进行 沟通交流 这个 沟通交流 的过程其实就是消息传递的过程 在没有操作系统的时候两个应用程序进行消息传递一般使用全局变量的方式 但是如果在使用操作系统的应用中用
  • Arduino IDE将FreeRTOS用于STM32

    介绍 适用于STM32F103C8的FreeRTOS STM32F103C是一种能够使用FreeRTOS的ARM Cortex M3处理器 我们直接在Arduino IDE中开始使用STM32F103C8的FreeRTOS 我们也可以使用K
  • STM32 Freertos 添加 外部sram heap_5.c

    1 添加外部SRAM 初始化 2 添加heap 5 c 3 初始化heap 5 c 外部堆栈 Define the start address and size of the two RAM regions not used by the
  • 13-FreeRTOS任务创建与删除

    任务创建和删除API函数位于文件task c中 需要包含task h头文件 task h里面包函数任务的类型函数 例如 对xTaskCreate的调用 通过指针方式 返回一个TaskHandle t 变量 然后可将该变量用vTaskDele
  • 当一个任务写入变量而其他任务读取该变量时,我们是否需要信号量?

    我正在研究 freeRtos 并且我有一个名为 x 的变量 现在 每秒只有一个任务正在写入该变量 而其他任务正在读取该变量值 我需要用互斥锁来保护变量吗 如果变量为 32 位或更小 并且其值是独立的并且不与任何其他变量一起解释 则不需要互斥
  • 如何更改 FreeRTOS 中任务的最大可用堆大小?

    我通过以下方式在任务中创建元素列表 l dllist pvPortMalloc sizeof dllist dlllist 有 32 字节大 我的嵌入式系统有 60kB SRAM 所以我希望系统可以轻松处理我的 200 个元素列表 我发现在
  • 防止GCC LTO删除函数

    我使用 GCC ARM Embedded 和 FreeRTOS FreeRTOS具有的功能vTaskSwitchContext 仅在某些情况下使用 内联汇编代码 问题是 当我使用LTO时 GCC不考虑内联汇编代码并认为该函数没有被使用 因此
  • C++ freeRTOS任务,非静态成员函数的无效使用

    哪里有问题 void MyClass task void pvParameter while 1 this gt update void MyClass startTask xTaskCreate this gt task Task 204

随机推荐

  • Pixhawk原生固件PX4之串口添加读取传感器实现

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 本博客承接前一篇 xff0c 对FreeApe的串口添加超声波传感器博文后半部分进行学习 为什么叫前奏呢 xff0c 因为用了伪传感器 xff0c 把单片机用串口发送
  • Pixhawk原生固件PX4之MAVLink协议解析

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a PX4 对Mavlink 协议提供了良好的原生支持 该协议既可以用于地面站 Ground ControlStation GCS 对无人机 UAV 的控制 xff0c
  • Pixhawk原生固件PX4之TAKEOFF的启动流程

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 以TAKEOFF为例说明PX4中一个飞行模式的启动流程 众所周知由遥控器或者地面站决定Main state作为用户期望到达的飞行模式然后有commander进行条件判
  • Pixhawk原生固件PX4之驱动ID

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 驱动ID PX4使用驱动ID将独立传感器贯穿于整个系统 这些ID存储于配置参数中 xff0c 用于匹配传感器校正值 xff0c 以及决定哪些传感器被记录到log中 传
  • Pixhawk原生固件PX4之SPI驱动注册过程

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 一切事出有因 xff0c 为了添加一个自定义SPI总线连接的传感器 xff0c 首先要弄清楚一个SPI设备的注册过程 xff0c 大致涉及以下的一些文件 接下来就该以
  • Pixhawk原生固件PX4之MPU6000驱动分析

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 要想自己添加一个传感器的话 xff0c 最好先搞明白已有的传感器的工作过程 这里记录一下PX4中MPU6000加速度计陀螺仪的解读过程 xff0c 从mpu6000
  • Pixhawk原生固件PX4之日期时间的确定

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 偶然注意到PX4日志中老是出现类似于2000 01 01 00 00 00这种日期 有兴趣的可以搜索一下千年虫问题 xff0c 于是结合代码进行了一波分析 最后定位到
  • Pixhawk原生固件PX4之添外置传感器MPU6500

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 成功的在Pixhawk上添加了一个自定义的传感器MPU6500 Pixhawk飞控板上空余出一个SPI4接口 提示 xff1a 多出来的GPIO EXT引脚可以作为片
  • 多旋翼无人机进阶教程

    无人机是一个系统的工程 xff0c 不可谓不庞大 开源飞控盛行 xff0c 重复造轮子的工作实在无需再做 但是若决定真正的去研究飞控 xff0c 必须从本质出发 xff0c 熟悉并了解其实现原理 纷繁复杂的资料 xff0c 让人无法分辨 笔
  • Pixhawk原生固件PX4之MAVLink外部通讯

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 目前的需求是 xff1a 一台电脑连数传 xff0c Pixhawk飞控上电连数传 xff0c 电脑向Pixhawk发送MAVlink消息 至少有5种方案 xff1a
  • rtsp流浏览器播放方案

    rtsp流在主流浏览器并不支持直接播放 比如大华的视频流 xff1a rtsp admin 123456 64 192 168 10 129 cam realmonitor channel 61 1 amp subtype 61 0 xff
  • PX4开发指南中文版维护说明

    PX4中文维基现已与PX4开发者官网合并 现在大家可以直接进入官网进行语言切换 PX4中文版的维护依然需要你的贡献 贡献说明 xff1a 官方的GitHub仓库为https github com PX4 Devguide 我将其Fork后的
  • OpenCV图像坐标系与行列宽高的关系

    刚开始接触图像处理 xff0c 关于图像坐标系与行列宽高的关系感到纠结 xff0c 但是似乎没有更好的处理方法了 xff0c 其对应关系大致如下 row 61 61 height 61 61 Point y col 61 61 width
  • Pixhawk原生固件PX4之位姿控制算法解读

    欢迎交流 个人 Gitter 交流平台 xff0c 点击直达 xff1a 参考文献 xff1a Minimum Snap Trajectory Generation and Control for Quadrotors PX4中多旋翼无人机
  • Pixhawk精准着陆之IRLock配置

    安装说明 下载Pixymon和pixy对应markone的固件 xff0c 在这里 固件必须是firmware IRLOCKpixy 1 0 1 hex irlock 61 markone 然后固件里 irlock 61 pixy 给Pix
  • Pixhawk原生固件PX4之offboard

    offboard PX4中的offboard 暂译作外部控制 是一个非常强大的功能 可以接受来自外部的控制指令 xff0c 按照目前的了解来看 xff0c offboard搭配上MAVROS以及类似于TX1 NUC板载计算器 xff0c 在
  • 相机标定原理

    cnblogs上的这篇讲相机标定的博文值得一看 csdn上这篇也可以参考 相机标定基础知识 相机标定技术涉及到一些数学原理和几何模型 xff0c 这些数学原理和几何模型是相机标定算法使用和进一步发展的基础 下面对相机标定技术中涉及到的齐次坐
  • VS Code的Git插件

    Visual Studio Code是微软公司推出的一款跨平台代码编辑 Edit 编译 Build 调试 Debug 工具 笔者认为其相当于是Sublime Text这款代码编辑器的升级版 集成了丰富的插件 xff0c 包括代码管理中极为常
  • Ubuntu缺少libncurses.so.5的解决办法

    执行arm none eabi gdb时候出错 xff1a arm none eabi gdb error while loading shared libraries libncurses so 5 cannot open shared
  • freeRTOS的任务抢占和时间片轮转

    实时操作系统的一个特点就是可以任务抢占 xff0c 高优先级的任务可以抢占比自己优先级低的任务 xff0c 如果新任务优先级和当前人任务优先级一样 xff0c 且在使能了时间片的方式的话 xff0c 二者以时间片的方式共享cpu xff0c