1899_野火FreeRTOS教程阅读笔记_任务创建

1899_野火FreeRTOS教程阅读笔记_任务创建

全部学习汇总: g_FreeRTOS: FreeRTOS学习笔记 (gitee.com)

关于这部分,从一般前后台程序到RTOS的任务描述了很多。但是我觉得这本书的这部分描述没有描述到关键的信息点。其实,RTOS存在的一个主要的目的就是让各个Task从Task自己的层面能够有一种感觉:Task自己独占了整个CPU。而Task本身是没法独占全部CPU的,我们多个Task都需要运行。这样,就需要从软件的层面来“模拟”的形式让Task能够感受到自己似乎独占了整个CPU一样。而堆栈空间的设计,其实就是为了实现这一点。

这个是一个精简的任务控制块的数据结构,其中比较关键的信息是堆栈信息以及任务节点。其中,任务节点会关联其他的用户代码。还剩下一个任务名字,这个对于RTOS的实现来说并不是那么重要。

书中的例子采用了静态创建任务的方式,这个其实我在自己使用这个OS的时候没用过,我创建任务的时候都用的动态的形式。放一个之前的使用方式代码如下:

xTaskCreate(prvPrintTaskA, "TaskA", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_RECEIVE_TASK_PRIORITY, NULL);
    xTaskCreate(prvPrintTaskB, "TaskB", configMINIMAL_STACK_SIZE, NULL, mainQUEUE_SEND_TASK_PRIORITY, NULL);

这个是动态创建任务时候的接口函数原型。两种方式的差异在于,现在教程中的部分是没有优先级处理的。另外就是静态的方式需要多一部分存储的处理,这个主要是因为静态不会再以内存申请分配的方式给任务分配内存,因此需要用户自己做这个存储的分派。至于句柄的处理,通过指针还是返回值的形式处理其实都差不多。但是,目前的句柄也只能看得出来是一个系统堆栈空间中的一个临时变量数值。而这个数值,应该会在进一步的初始化中进行修改。

要进一步了解这部分功能,得借助以SICP提到的黑盒抽象。需要知道,prvInitialiseNewTask()接口会完成实际的任务创建的工作,而这个创建接口会同时给出是否创建成功的一个提示。而这个接口用的句柄处理形式,其实是跟我之前使用的动态创建是类似的。

static void prvInitialiseNewTask(TaskFunction_t pxTaskCode,         /* 任务入口 */
                                 const char *const pcName,          /* 任务名称,字符串形式 */
                                 const uint32_t ulStackDepth,       /* 任务栈大小,单位为字 */
                                 void *const pvParameters,          /* 任务形参 */
                                 TaskHandle_t *const pxCreatedTask, /* 任务句柄 */
                                 TCB_t *pxNewTCB)                   /* 任务控制块指针 */

{
    StackType_t *pxTopOfStack;
    UBaseType_t x;

    /* 获取栈顶地址 */
    pxTopOfStack = pxNewTCB->pxStack + (ulStackDepth - (uint32_t)1);
    /* 向下做8字节对齐 */
    pxTopOfStack = (StackType_t *)(((uint32_t)pxTopOfStack) & (~((uint32_t)0x0007)));

    /* 将任务的名字存储在TCB中 */
    for (x = (UBaseType_t)0; x < (UBaseType_t)configMAX_TASK_NAME_LEN; x++)
    {
        pxNewTCB->pcTaskName[x] = pcName[x];

        if (pcName[x] == 0x00)
        {
            break;
        }
    }
    /* 任务名字的长度不能超过configMAX_TASK_NAME_LEN */
    pxNewTCB->pcTaskName[configMAX_TASK_NAME_LEN - 1] = '\0';

    /* 初始化TCB中的xStateListItem节点 */
    vListInitialiseItem(&(pxNewTCB->xStateListItem));
    /* 设置xStateListItem节点的拥有者 */
    listSET_LIST_ITEM_OWNER(&(pxNewTCB->xStateListItem), pxNewTCB);

    /* 初始化任务栈 */
    pxNewTCB->pxTopOfStack = pxPortInitialiseStack(pxTopOfStack, pxTaskCode, pvParameters);

    /* 让任务句柄指向任务控制块 */
    if ((void *)pxCreatedTask != NULL)
    {
        *pxCreatedTask = (TaskHandle_t)pxNewTCB;
    }
}

上面是这个新任务初始化接口prvInitialiseNewTask()的实现。既然,处理的主要元素信息是堆栈以及任务控制块。那么具体的操作是做了什么呢?

先看堆栈。堆栈在这个接口中其实主要的处理是做了一个对齐的处理,对齐处理的操作是:根据静态任务创建接口xTaskCreateStatic()中传入的静态创建所分配的存储buffer所指向的内存做一个对齐的处理。而这个buffer的信息,在上一层的接口中已经完成了与TCB的信息绑定。这个对齐的要求主要是MCU的架构决定的,这里是按照8个字节来对齐,主要就是考虑了浮点运算时候的一个对齐。关于这个原因,我之前的确是没有弄清楚,还是从这个教材中学来的。这个对齐,进一步划定了这个任务堆栈所用的RAM范围。至于下一步的堆栈如何处理,再一步采用黑盒抽象。

任务控制块的处理,是把任务控制块中绑定的链表节点信息进行初始化,之后设置链表元素节点的处理对象绑定关系。即把TCB的信息绑定到这个链表节点上。不过,到此为止看得出来,暂时这个节点还是没有形成链表关系。因为少了插入的操作。

关于句柄的处理,可以看得出来这个句柄最终被处理成了指向TCB的指针的数值,也可以理解为是TCB的地址数值。

这样,如果要理解任务的创建,我们就还需要进一步分析前面黑盒抽象接口:堆栈的初始化处理接口pxPortInitialiseStack()

StackType_t *pxPortInitialiseStack(StackType_t *pxTopOfStack, TaskFunction_t pxCode, void *pvParameters)
{
    /* 异常发生时,自动加载到CPU寄存器的内容 */
    pxTopOfStack--;
    *pxTopOfStack = portINITIAL_XPSR; /* xPSR的bit24必须置1 */
    pxTopOfStack--;
    *pxTopOfStack = ((StackType_t)pxCode) & portSTART_ADDRESS_MASK; /* PC,即任务入口函数 */
    pxTopOfStack--;
    *pxTopOfStack = (StackType_t)prvTaskExitError; /* LR,函数返回地址 */
    pxTopOfStack -= 5;                             /* R12, R3, R2 and R1 默认初始化为0 */
    *pxTopOfStack = (StackType_t)pvParameters;     /* R0,任务形参 */

    /* 异常发生时,手动加载到CPU寄存器的内容 */
    pxTopOfStack -= 8; /* R11, R10, R9, R8, R7, R6, R5 and R4默认初始化为0 */

    /* 返回栈顶指针,此时pxTopOfStack指向空闲栈 */
    return pxTopOfStack;
}

首先要理解这个栈的处理方式,栈的增长是从上到下的,因此上面的地址会是一个递减的处理过程。

至于堆栈中存储了什么内容,这里有一个具体的说明。为什么这么安排,之前的经验是直接看ARM相关内核手册中的编程模型。这样,这段处理把指针挪到了这一堆寄存器镜像的最后面,也就是图中空闲堆栈的最上面。该信息记录在任务控制块中,后续在任务执行的时候使用。

至此为止,整个操作其实还只是准备了数据结构的信息。暂时,相应的TCB还没有任何与链表产生关联的动作。而任务调度其实是基于链表的,因此到此还看不出任何调度可能出现的痕迹。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

UML 2.5图形库

UML 2.5图形库 drawio是一款强大的图表绘制软件&#xff0c;支持在线云端版本以及windows, macOS, linux安装版。 如果想在线直接使用&#xff0c;则直接输入网址drawon.cn或者使用drawon(桌案), drawon.cn内部完整的集成了drawio的所有功能&#xff0c;并实现了云端存储&#…

一文读懂:MybatisPlus从入门到进阶

快速入门 简介 在项目开发中&#xff0c;Mybatis已经为我们简化了代码编写。 但是我们仍需要编写很多单表CURD语句&#xff0c;MybatisPlus可以进一步简化Mybatis。 MybatisPlus官方文档&#xff1a;https://www.baomidou.com/&#xff0c;感谢苞米豆和黑马程序员。 Mybat…

Spring Boot的打包方式:JAR vs. WAR 打包方式

Spring Boot的打包方式&#xff1a;JAR vs. WAR 打包方式 Spring Boot是一个流行的Java开发框架&#xff0c;提供了快速、便捷的应用程序开发和部署方式。本文将介绍Spring Boot的两种常见打包方式&#xff1a;JAR和WAR。我们将深入探讨它们的特点、适用场景和部署方式&#xf…

使用命令修复windows 7/8引导,解决GHO映像恢复后不能进入系统的问题

背景&#xff1a; 最近使用ghost恢复windows7的GHO系统映像&#xff0c;重启后找不到引导系统。原因是没有激活系统分区。而之前安装在系统上的PE系统已经被删除。此时手里只有一个windows 10的启动u盘。可谓是绝望。 解决办法&#xff1a; 启动windows10系统u盘&#xff0c;点…

【python】绘制春节烟花

一、Pygame库春节烟花示例 下面是一个使用Pygame实现的简单春节烟花效果的示例代码。请注意&#xff0c;运行下面的代码之前&#xff0c;请确保计算机上已经安装了Pygame库。 import pygame import random import math from pygame.locals import *# 初始化pygame pygame.ini…

4.4 特效优化注意点

一、特效模型制作标准和注意事项 1.特效模型面数最大500&#xff08;面数可以加到1000&#xff0c;但是要分Lod等级&#xff09; &#xff08;模型对打面熟需要根据项目需求做好规范&#xff0c;例如Lod0 1000Tris&#xff0c; Lod1...Lod3 100Tris&#xff0c;最好以引擎内的三…

Sklearn、TensorFlow 与 Keras 机器学习实用指南第三版(八)

原文&#xff1a;Hands-On Machine Learning with Scikit-Learn, Keras, and TensorFlow 译者&#xff1a;飞龙 协议&#xff1a;CC BY-NC-SA 4.0 第十八章&#xff1a;强化学习 强化学习&#xff08;RL&#xff09;是当今最激动人心的机器学习领域之一&#xff0c;也是最古老…

VMwawre配置静态ip

1、查看当前虚拟机网关&#xff08;记住这个网关&#xff0c;后面使用&#xff09; 2、进入目录命令&#xff1a;cd /etc/sysconfig/network-scripts/ 3、编辑网卡配置文件命令&#xff1a;vim ifcfg-ens33 4、配置静态IP&#xff0c;修改和增加如下信息&#xff1a; 修改的内…

编码技巧——在项目中使用Alibaba Cloud Toolkit远程部署

背景 在新公司项目开发&#xff0c;当前项目为自建项目&#xff0c;意思是从开发到运维都需要自己负责&#xff0c;远程的服务器也是自己搭建的win操作系统&#xff1b; 之前在大厂工作时&#xff0c;一般提交代码之后&#xff0c;CICD流水线会自动的执行最新代码的拉取、构建打…

神经网络 | 常见的激活函数

Hi&#xff0c;大家好&#xff0c;我是半亩花海。本文主要介绍神经网络中必要的激活函数的定义、分类、作用以及常见的激活函数的功能。 目录 一、激活函数定义 二、激活函数分类 三、常见的几种激活函数 1. Sigmoid 函数 &#xff08;1&#xff09;公式 &#xff08;2&a…

Linux笔记之expect和bash脚本监听输出并在匹配到指定字符串时发送中断信号

Linux笔记之expect和bash脚本监听输出并在匹配到指定字符串时发送中断信号 code review! 文章目录 Linux笔记之expect和bash脚本监听输出并在匹配到指定字符串时发送中断信号1.expect2.bash 1.expect 在Expect脚本中&#xff0c;你可以使用expect来监听程序输出&#xff0c;…

Redis——高级主题

介绍Redis的高级主题&#xff0c;包括服务器配置、Redis事务、Redis发布和订阅、Pipeline批量发送请求、数据备份与恢复等。 1、服务器配置 在Windows和Linux的Redis服务器里面&#xff0c;都有一个配置文件。Redis配置文件位于Redis安装目录下&#xff0c;在不同操作系统下&…

VMWare下载安装(包含Window是和Mac)

VMWare下载安装&#xff08;包含Window是和Mac&#xff09; 文章目录 VMWare下载安装&#xff08;包含Window是和Mac&#xff09;一、windows下载VMWare①&#xff1a;下载01&#xff1a;网盘下载02&#xff1a;官方下载 ②&#xff1a;安装③&#xff1a;密钥 二、Mac下载VMWa…

vue3:26—新的内置组件

目录 Teleport Suspense Teleport 什么是Teleport? Teleport 是一种能够将我们的组件html结构移动到指定位置的技术 当在元素中的css使用了filter滤镜属性的时候&#xff0c;会导致内部 fixed 元素定位发生错误&#xff0c;即不再相对 viewport 进行定位&#xff0c;而是相对…

使用 WMI 查询安全软件信息

在这篇文章中&#xff0c;我们将详细介绍如何使用 Windows Management Instrumentation (WMI) API 来查询当前计算机上安装的安全软件的基本信息。我们将分析代码的各个部分&#xff0c;并解释每个步骤所涉及的技术和原理。 一、什么是 WMI&#xff1f; WMI 是 Windows Manag…

BlueLotus 下载安装使用

说明 蓝莲花平台BlueLotus&#xff0c;是清华大学曾经的蓝莲花战队搭建的平台&#xff0c;该平台用于接收xss返回数据。 正常执行反射型xss和存储型xss&#xff1a; 反射型在执行poc时&#xff0c;会直接在页面弹出执行注入的poc代码&#xff1b;存储型则是在将poc代码注入用…

基于51 单片机的交通灯系统 源码+仿真+ppt

主要内容&#xff1a; 1&#xff09;南北方向的绿灯、东西方向的红灯同时亮40秒。 2&#xff09;南北方向的绿灯灭、黄灯亮5秒&#xff0c;同时东西方向的红灯继续亮。 3&#xff09;南北方向的黄灯灭、左转绿灯亮&#xff0c;持续20秒&#xff0c;同时东西方向的红灯继续…

Spinnaker多云持续交付平台: 部署Minio存储服务

目录 一、实验 1.环境 2.K8S storage节点部署NFS 3.K8S 动态创建PV 4.K8S master节点部署HELM3 4.K8S master节点部署Minio存储服务&#xff08;第一种方式安装&#xff09; 5.Minio客户端安装MC命令 6.K8S master节点使用Docker 部署Minio存储服务&#xff08;第二种方…

设计模式学习笔记05(小滴课堂)

讲解Adapeter设计模式和应用场景 接口的适配器案例实战 代码&#xff1a; 定义一个接口&#xff1a; 编写适配器&#xff1a; 写我们的商品类&#xff1a; 会员类&#xff1a; 这样我们不同的需求可以根据需要去实现不同的接口方法&#xff0c;而不用实现全部接口方法。 适配…

elasticsearch重置密码操作

安装es的时候需要测试这个url&#xff1a;http://127.0.0.1:9200/ 出现弹窗让我输入账号和密码。我第一次登录&#xff0c;没有设置过账号和密码&#xff0c; 解决方法是&#xff1a;在es的bin目录下打开cmd窗口&#xff0c;敲命令&#xff1a;.\elasticsearch-reset-password…