实时操作系统Freertos开坑学习笔记:(五):任务调度和时间片调度

news2024/12/28 3:21:38

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录

  • 前言
  • 一、任务调度
    • 1.开启任务调度器函数
    • 2.启动第一个任务
  • 二、任务切换的原理
  • 三、时间片调度
    • 1.基本概念
    • 2.看一个实际例程
      • ①我们设置滴答定时器中断时间为50ms,即一个时间片是50ms,那么任务一有一个delay10ms的延时(这里不能用系统非阻塞延时),算上延时和打印语句,总共可能会执行四次左右,然后一个时间片消耗完,转向任务二也执行4次,二者循环往复
      • ②为什么要加入临界区保护呢?
      • ③现象不解释了,就是次数不断增大。


前言

不多逼逼,直接上内容:
在这里插入图片描述
在这里插入图片描述
这些内容基本上都是讲解源码,比较深,比较枯燥。

一、任务调度

1.开启任务调度器函数

在这里插入图片描述

void vTaskStartScheduler( void )
{
    BaseType_t xReturn;

    /* Add the idle task at the lowest priority. */
    #if ( configSUPPORT_STATIC_ALLOCATION == 1 )
        {
            StaticTask_t * pxIdleTaskTCBBuffer = NULL;
            StackType_t * pxIdleTaskStackBuffer = NULL;
            uint32_t ulIdleTaskStackSize;

            /* The Idle task is created using user provided RAM - obtain the
             * address of the RAM then create the idle task. */
            vApplicationGetIdleTaskMemory( &pxIdleTaskTCBBuffer, &pxIdleTaskStackBuffer, &ulIdleTaskStackSize );
            xIdleTaskHandle = xTaskCreateStatic( prvIdleTask,
                                                 configIDLE_TASK_NAME,
                                                 ulIdleTaskStackSize,
                                                 ( void * ) NULL,       /*lint !e961.  The cast is not redundant for all compilers. */
                                                 portPRIVILEGE_BIT,     /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                                 pxIdleTaskStackBuffer,
                                                 pxIdleTaskTCBBuffer ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */

            if( xIdleTaskHandle != NULL )
            {
                xReturn = pdPASS;
            }
            else
            {
                xReturn = pdFAIL;
            }
        }
    #else /* if ( configSUPPORT_STATIC_ALLOCATION == 1 ) */
        {
            /* The Idle task is being created using dynamically allocated RAM. */
            xReturn = xTaskCreate( prvIdleTask,
                                   configIDLE_TASK_NAME,
                                   configMINIMAL_STACK_SIZE,
                                   ( void * ) NULL,
                                   portPRIVILEGE_BIT,  /* In effect ( tskIDLE_PRIORITY | portPRIVILEGE_BIT ), but tskIDLE_PRIORITY is zero. */
                                   &xIdleTaskHandle ); /*lint !e961 MISRA exception, justified as it is not a redundant explicit cast to all supported compilers. */
        }
    #endif /* configSUPPORT_STATIC_ALLOCATION */

    #if ( configUSE_TIMERS == 1 )
        {
            if( xReturn == pdPASS )
            {
                xReturn = xTimerCreateTimerTask();
            }
            else
            {
                mtCOVERAGE_TEST_MARKER();
            }
        }
    #endif /* configUSE_TIMERS */

    if( xReturn == pdPASS )
    {
        /* freertos_tasks_c_additions_init() should only be called if the user
         * definable macro FREERTOS_TASKS_C_ADDITIONS_INIT() is defined, as that is
         * the only macro called by the function. */
        #ifdef FREERTOS_TASKS_C_ADDITIONS_INIT
            {
                freertos_tasks_c_additions_init();
            }
        #endif

        /* Interrupts are turned off here, to ensure a tick does not occur
         * before or during the call to xPortStartScheduler().  The stacks of
         * the created tasks contain a status word with interrupts switched on
         * so interrupts will automatically get re-enabled when the first task
         * starts to run. */
        portDISABLE_INTERRUPTS();

        #if ( configUSE_NEWLIB_REENTRANT == 1 )
            {
                /* Switch Newlib's _impure_ptr variable to point to the _reent
                 * structure specific to the task that will run first.
                 * See the third party link http://www.nadler.com/embedded/newlibAndFreeRTOS.html
                 * for additional information. */
                _impure_ptr = &( pxCurrentTCB->xNewLib_reent );
            }
        #endif /* configUSE_NEWLIB_REENTRANT */

        xNextTaskUnblockTime = portMAX_DELAY;
        xSchedulerRunning = pdTRUE;
        xTickCount = ( TickType_t ) configINITIAL_TICK_COUNT;

        /* If configGENERATE_RUN_TIME_STATS is defined then the following
         * macro must be defined to configure the timer/counter used to generate
         * the run time counter time base.   NOTE:  If configGENERATE_RUN_TIME_STATS
         * is set to 0 and the following line fails to build then ensure you do not
         * have portCONFIGURE_TIMER_FOR_RUN_TIME_STATS() defined in your
         * FreeRTOSConfig.h file. */
        portCONFIGURE_TIMER_FOR_RUN_TIME_STATS();

        traceTASK_SWITCHED_IN();

        /* Setting up the timer tick is hardware specific and thus in the
         * portable interface. */
        if( xPortStartScheduler() != pdFALSE )
        {
            /* Should not reach here as if the scheduler is running the
             * function will not return. */
        }
        else
        {
            /* Should only reach here if a task calls xTaskEndScheduler(). */
        }
    }
    else
    {
        /* This line will only be reached if the kernel could not be started,
         * because there was not enough FreeRTOS heap to create the idle task
         * or the timer task. */
        configASSERT( xReturn != errCOULD_NOT_ALLOCATE_REQUIRED_MEMORY );
    }

    /* Prevent compiler warnings if INCLUDE_xTaskGetIdleTaskHandle is set to 0,
     * meaning xIdleTaskHandle is not used anywhere else. */
    ( void ) xIdleTaskHandle;

    /* OpenOCD makes use of uxTopUsedPriority for thread debugging. Prevent uxTopUsedPriority
     * from getting optimized out as it is no longer used by the kernel. */
    ( void ) uxTopUsedPriority;
}

比较复杂而且难,我也看不懂。后面再说。
在这里插入图片描述

2.启动第一个任务

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
只能说这部分确实是枯燥难懂,我目前也不想花时间了解,等以后有时间再来深入探究吧。

二、任务切换的原理

在这里插入图片描述
任务切换的本质:就是CPU寄存器的切换。
假设当由任务A切换到任务B时,主要分为两步:
第一步:需暂停任务A的执行,并将此时任务A的寄存器保存到任务堆栈,这个过程叫做保存现场;
第二步:将任务B的各个寄存器值(被存于任务堆栈中)恢复到CPU寄存器中,这个过程叫做恢复现场;对任务A保存现场,对任务B恢复现场,这个整体的过程称之为:上下文切换
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
也很复杂,我也不想去深入了解,哎。就先留个图。

三、时间片调度

1.基本概念

在这里插入图片描述
首先,时间片调度机制是针对同等优先级的任务的。
其次,一个时间片大小:在FreeRTOS中,一个时间片就等于SysTick 中断周期,也就是1ms。
重点是这几句话:
在这里插入图片描述

2.看一个实际例程

在这里插入图片描述
注意,两个任务的优先级要相同。
代码如下(示例):

/* 任务一,实现LED0每500ms翻转一次 */
void task1( void * pvParameters )
{
    uint32_t task1_num = 0;
    while(1)
    {
        taskENTER_CRITICAL();               /* 进入临界区 */
        printf("task1运行次数:%d\r\n",++task1_num);
        taskEXIT_CRITICAL();                /* 退出临界区 */
        delay_ms(10);
    }
}

/* 任务二,列表项的插入和删除实验 */
void task2( void * pvParameters )
{
    uint32_t task2_num = 0;
    while(1)
    {
        taskENTER_CRITICAL();               /* 进入临界区 */
        printf("task2运行次数:%d\r\n",++task2_num);
        taskEXIT_CRITICAL();                /* 退出临界区 */
        delay_ms(10);
    }
}

①我们设置滴答定时器中断时间为50ms,即一个时间片是50ms,那么任务一有一个delay10ms的延时(这里不能用系统非阻塞延时),算上延时和打印语句,总共可能会执行四次左右,然后一个时间片消耗完,转向任务二也执行4次,二者循环往复

②为什么要加入临界区保护呢?

答:因为 printf(“task1运行次数:%d\r\n”,++task1_num);这个语句的执行也会花一点时间,那么如果不加临界段保护,当每执行到第五次时,可能还没有把文本打印完,就到了50ms的时间片了,导致立刻跳到另一个任务执行,使得数据不完整。

③现象不解释了,就是次数不断增大。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/974176.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

低代码平台:IVX 重新定义编程

目录 🍬一、写在前面 🍬二、低代码平台是什么 🍬三、为什么程序员和技术管理者不太可能接受“低代码”平台? 🍭1、不安全(锁定特性) 🍭2、不信任 🍬四、IVX低代码平台 &a…

Vue3数值动画(NumberAnimation)

效果如下图:在线预览 APIs 参数说明类型默认值必传from数值动画起始数值number0falseto数值目标值number1000falseduration数值动画持续时间,单位msnumber3000falseautoplay是否自动开始动画booleantruefalseprecision精度,保留小数点后几位…

vue响应式详解

1. 响应式的定义 我们都知道,vue是基于javascript的,那我们使用一段javascript代码来描述响应式 let a 1,b 1,c; c a b; console.log(c) // 输出 2 // 改变 a的值 a 3; // 重新给c赋值 即把 c a b; 再执行一遍c的值才能变为 4 // c a b; // …

map组件轨迹,定位,导航,定位点遮罩

小程序使用map组件实现轨迹&#xff0c;定位&#xff0c;导航&#xff0c;定位点遮罩 map组件常用属性说明&#xff0c; 看着还要自己研究写 我们立志成为cv工程师 直接上代码&#xff01;&#xff01;&#xff01; <template><map id"map" class"m…

天软高频因子日内及隔夜动量因子

天软因子序列课程再次启动&#xff0c;本周四&#xff08;9月7日&#xff09;下午4点相约腾讯会议&#xff0c;可直接扫描下方二维码&#xff0c;欢迎大家参会&#xff01; 本次会议主要内容有&#xff1a; 1.介绍日内及隔夜动量因子的构造逻辑&#xff0c;如何选择市 场代理变…

Spring AOP与静态代理/动态代理

文章目录 一、代理模式静态代理动态代理代理模式与AOP 二、Spring AOPSping AOP用来处理什么场景jdk 动态代理cglib 动态代理面试题&#xff1a;讲讲Spring AOP的原理与执行流程 总结 一、代理模式 代理模式是一种结构型设计模式&#xff0c;它允许对象提供替代品或占位符&…

说说MySQL主从复制?

分析&回答 主从复制原理 主库记录binlog日志 在每次准备提交事务完成数据更新前&#xff0c;主库将数据更新的事件记录到二进制日志binlog中。主库上的sync_binlog参数控制binlog日志刷新到磁盘。 从库IO线程将主库的binlog日志复制到其本地的中继日志relay log中 从库会…

K8S的CKA考试环境和题目

CKA考试这几年来虽然版本在升级&#xff0c;但题目一直没有大的变化&#xff0c;通过K8S考试的方法就是在模拟环境上反复练习&#xff0c;通过练习熟悉考试环境和考试过程中可能遇到的坑。这里姚远老师详细向大家介绍一下考试的环境和题目&#xff0c;需要详细资料的同学请在文…

解决C++ 遇笔试题输入[[1,2,3,...,],[5,6,...,],...,[3,1,2,...,]]问题

目录 0 引言1 思路2 测试结果3 完整代码4 总结 0 引言 现在面临找工作问题&#xff0c;做了几场笔试&#xff0c;遇到了一个比较棘手的题目就是题目输入形式如下&#xff1a; [ [3,1,1], [3,5,3], [3,2,1] ] 当时遇到这个问题还是比较慌的&#xff0c;主要是之前没有遇到这样的…

RHCA之路---EX280(2)

RHCA之路—EX280(2) 1. 题目 Associate the share named /exports/registry to the built-in registry running within your OpenShift Enterprise instance so that it will be used for permanent storage Use exam-registry-volume for the volume name and exam-registry-…

公司内部传文件怎么安全——「用绿盾透明加密软件」

为保证公司内部文件传递的安全性&#xff0c;可以使用天锐绿盾透明加密软件来进行保护。以下是具体的操作步骤&#xff1a; 在公司内部部署天锐绿盾加密软件&#xff0c;确保需要传递的文件都能受到加密保护。 在员工的工作电脑上安装天锐绿盾客户端&#xff0c;并设置好相关的…

C++学习记录——삼십이 C++IO流

文章目录 1、C标准IO流2、C文件IO流1、二进制读写2、文本读写 3、stringstream 1、C标准IO流 C语言的printf和scanf无法很好的输入输出自定义类型&#xff0c;且还需要程序员自己确定类型&#xff0c;所以C就引入了输入流和输出流&#xff0c;是设备和内存之间的沟通。 其实io…

Gin学习记录3——模版与渲染

模版与渲染 一. 返回二. 模版2.1 基础模版2.2 同名模版2.3 模版继承2.4 模版语法 一. 返回 如果只是想返回数据&#xff0c;可以使用以下函数&#xff1a; func (c *Context) JSON(code int, obj any) func (c *Context) JSONP(code int, obj any) func (c *Context) String(…

阿里后端开发:抽象建模经典案例

0.引言 在互联网行业&#xff0c;软件工程师面对的产品需求大都是以具象的现实世界事物概念来描述的&#xff0c;遵循的是人类世界的自然语言&#xff0c;而软件世界里通行的则是机器语言&#xff0c;两者间跨度太大&#xff0c;需要一座桥梁来联通&#xff0c;抽象建模便是打…

一文读懂HOOPS Native平台:快速开发桌面端、移动端3D应用程序!

HOOPS Native Platform是用于在桌面和移动平台以及混合现实应用程序上构建3D工程应用程序的首要工具包。它由三个集成良好的软件开发工具包(SDK)组成&#xff1a;HOOPS Visualize、HOOPS Exchange、HOOPS Publish。HOOPS Visualize 是一个强大的图形引擎&#xff0c;适用于本机…

lement-ui 加载本地图片

实现图片展示时&#xff0c;发先本地的图片加载不了。 代码&#xff1a; <template><div><el-image src"../assets/logo.png" ></el-image></div> </template>结果发现不对&#xff0c;加载不出来&#xff0c;一查资料&#xf…

【Java】Jxls--轻松生成 Excel

1、介绍 Jxls 是一个小型 Java 库&#xff0c;可以轻松生成 Excel 报告。Jxls 在 Excel 模板中使用特殊标记来定义输出格式和数据布局。 Java 有一些用于创建 Excel 文件的库&#xff0c;例如Apache POI。这些库都很好&#xff0c;但都是一些较底层的库&#xff0c;因为它们要…

代码随想录算法训练营第42天 | ● 01背包问题,你该了解这些! ● 01背包问题,你该了解这些! 滚动数组 ● 416. 分割等和子集

文章目录 前言一、01背包问题&#xff0c;你该了解这些&#xff01;二、01背包问题&#xff0c;你该了解这些&#xff01; 滚动数组三、416. 分割等和子集总结 前言 01背包 一、01背包问题&#xff0c;你该了解这些&#xff01; 确定dp数组以及下标的含义 对于背包问题&#x…

2605. 从两个数字数组里生成最小数字

文章目录 Tag题目来源题目解读解题思路方法一&#xff1a;枚举比较法方法二&#xff1a;集合的位运算表示法 写在最后 Tag 【贪心】【位运算】【数组】 题目来源 2605. 从两个数字数组里生成最小数字 题目解读 给定两个各自只包含数字 1 到 9 的两个数组&#xff0c;每个数组…

git中的cherry-pick和merge有些区别以及cherry-pick怎么用

git中的cherry-pick和merge在使用场景上有些区别: cherry-pick用于将另一个分支的某一次或几次commit应用到当前分支。它可以选择性地拉取代码修改。merge用于将两个分支合并成一个新分支。它会把整个分支上的所有修改都合并过来。 具体区别:cherry-pick通常用于将bug修复从发…