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还没有任何与链表产生关联的动作。而任务调度其实是基于链表的,因此到此还看不出任何调度可能出现的痕迹。

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

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

相关文章

机器学习系列——(十七)聚类

引言 在当今数据驱动的时代&#xff0c;机器学习已经成为了解锁数据潜能的关键技术之一。其中&#xff0c;聚类作为机器学习领域的一个重要分支&#xff0c;广泛应用于数据挖掘、模式识别、图像分析等多个领域。本文旨在深入探讨聚类技术的原理、类型及其应用&#xff0c;为读…

【Flink入门修炼】1-3 Flink WordCount 入门实现

本篇文章将带大家运行 Flink 最简单的程序 WordCount。先实践后理论&#xff0c;对其基本输入输出、编程代码有初步了解&#xff0c;后续篇章再对 Flink 的各种概念和架构进行介绍。 下面将从创建项目开始&#xff0c;介绍如何创建出一个 Flink 项目&#xff1b;然后从 DataStr…

IDEA创建Java类时自动添加注释(作者、年份、月份)

目录 IDEA创建Java类时自动添加注释&#xff08;作者、年份、月份&#xff09;如图&#xff1a; IDEA创建Java类时自动添加注释&#xff08;作者、年份、月份&#xff09; 简单记录下&#xff0c;IDEA创建Java类时自动添加注释&#xff08;作者、年份、月份&#xff09;&#…

Java+微信小程序实现智慧家政系统 JAVA+Vue+SpringBoot+MySQL

目录 一、摘要1.1 项目介绍1.2 项目录屏 二、功能模块三、系统展示四、核心代码4.1 查询家政服务4.2 新增单条服务订单4.3 新增留言反馈4.4 小程序登录4.5 小程序数据展示 五、免责说明 一、摘要 1.1 项目介绍 基于微信小程序JAVAVueSpringBootMySQL的智慧家政系统&#xff0…

作业2.8

1、选择题 1.1、以下选项中,不能作为合法常量的是 ____B______ A&#xff09;1.234e04 B&#xff09;1.234e0.4 C&#xff09;1.234e4 D&#xff09;1.234e0 1.2、以下定义变量并初始化错误的是_____D________。 A) char c1 ‘H’ &#xff1b; B) char c…

RabbitMQ高可用架构涉及常用功能整理

RabbitMQ高可用架构涉及常用功能整理 1. rabbitmq的集群模式2. 镜像模式高可用系统架构和相关组件3. rabbitmq的核心参数3.1 镜像策略3.2 新镜像同步策略3.3 从节点晋升策略3.4 主队列选择策略 4. rabbitmq常用命令4.1 常用基础命令4.1.1 服务管理4.1.2 用户管理4.1.3 角色管理…

数字图像处理(实践篇)四十七 OpenCV-Python 高动态范围HDR

目录 一 HDR 二 实践 高质量的图像具备的要素如下: ①分辨率 图像中的像素数量。在特定屏幕尺寸下,分辨率越高,像素越多,显示的细节更精细。 ②位深度

JavaEE作业-实验三

目录 1 实验内容 2 实验要求 3 思路 4 核心代码 5 实验结果 1 实验内容 简单的线上图书交易系统的web层 2 实验要求 ①采用SpringMVC框架&#xff0c;采用REST风格 ②要求具有如下功能&#xff1a;商品分类、订单、购物车、库存 ③独立完成&#xff0c;编写实验报告 …

自然语言处理(NLP)——使用Rasa创建聊天机器人

1 基本概念 1.1 自然语言处理的分类 IR-BOT&#xff1a;检索型问答系统 Task-bot&#xff1a;任务型对话系统 Chitchat-bot:闲聊系统 1.2 任务型对话Task-Bot:task-oriented bot 这张图展示了一个语音对话系统&#xff08;或聊天机器人&#xff09;的基本组成部分和它们之间的…

外贸邮件群发如何做?外贸邮件群发靠谱吗?

外贸邮件群发有哪些平台&#xff1f;外贸群发邮件用什么邮箱&#xff1f; 外贸邮件群发是许多企业在开展国际贸易时常用的营销手段&#xff0c;它不仅能够快速地将产品信息和促销活动传达给目标客户&#xff0c;还能够有效地建立和维护客户关系。下面&#xff0c;就让蜂邮探讨…

跟着pink老师前端入门教程-day21+22

5.4 常见flex布局思路 5.5 背景线性渐变 语法&#xff1a; background: linear-gradient( 起始方向 , 颜色 1, 颜色 2, ...); background: -webkit-linear-gradient(left, red , blue); background: -webkit-linear-gradient(left top, red , blue); 背景渐变必须添加浏览…

e5 服务器具备哪些性能特点?

随着云计算和大数据技术的不断发展&#xff0c;服务器作为数据中心的核心设备&#xff0c;其性能特点也日益受到关注。其中&#xff0c;E5服务器作为当前主流的服务器类型之一&#xff0c;具备许多优秀的性能特点。本文将详细介绍E5服务器的性能特点&#xff0c;帮助读者更好地…

CTFshow web(php命令执行 37-40)

?ceval($_GET[shy]);&shypassthru(cat flag.php); #逃逸过滤 ?cinclude%09$_GET[shy]?>&shyphp://filter/readconvert.base64-encode/resourceflag.php #文件包含 ?cinclude%0a$_GET[cmd]?>&cmdphp://filter/readconvert.base64-encode/…

【我与Java的成长记】之String类详解

系列文章目录 能看懂文字就能明白系列 C语言笔记传送门 Java笔记传送门 &#x1f31f; 个人主页&#xff1a;古德猫宁- &#x1f308; 信念如阳光&#xff0c;照亮前行的每一步 文章目录 系列文章目录&#x1f308; *信念如阳光&#xff0c;照亮前行的每一步* 前言一、字符串构…

【http】2、http request header Origin 属性、跨域 CORS、同源、nginx 反向代理、预检请求

文章目录 一、Origin 含义二、跨源资源共享&#xff1a;**Cross-Origin Resource Sharing** CORS2.1 跨域的定义2.2 功能概述2.3 场景示例2.3.1 简单请求2.3.2 Preflighted requests&#xff1a;预检请求 2.4 header2.4.1 http request header2.4.1.1 Origin2.4.1.2 Access-Con…

立面效果图为何要用云渲染100?渲染100邀请码1a12

建筑设计是一门艺术&#xff0c;而立面效果图是艺术的展现&#xff0c;它在设计中非常重要。 1、立面效果图的重要性 立面效果图能用来展示建筑物的风格、材质、色彩以及环境等因素&#xff0c;通过它&#xff0c;设计师可以检验项目质量&#xff0c;评估效果是否达到预期&…

(2024,低比特模型量化,模型微调,QuEST,TAQuant)QuEST:通过高效选择性微调进行低比特扩散模型量化

QuEST: Low-bit Diffusion Model Quantization via Efficient Selective Finetuning 公和众和号&#xff1a;EDPJ&#xff08;进 Q 交流群&#xff1a;922230617 或加 VX&#xff1a;CV_EDPJ 进 V 交流群&#xff09; 目录 0. 摘要 2. 相关工作 3. 方法 3.1. 预备知识 3…

ELAdmin 的 CRUD

数据表结构 弄个测试的数据表&#xff0c;不同类型的几个字段&#xff0c;表名位 mp_reply。 生成代码 ELAdmin 可以自动生成代码。 左侧目录系统工具–代码生成&#xff0c;点开以后可以看到上面创建的数据表mp_reply&#xff0c;点击配置。 进入的页面内容有两部分&#…

DePIN+GameFi+顶级电竞团队,GAIMIN如何颠覆Web3游戏赛道

DePIN带动互联网进入去中心化时代 自从智能合约和去中心化应用DApp普及之后&#xff0c;越来越多的从业者开始将目光放在区块链对互联网的升级和改造之上&#xff0c;这里主要进行了三类&#xff0c;第一类是通过节点的去中心化来实现的&#xff0c;这样确保了基础设施的分散&a…

Zoho Mail企业邮箱商业扩展第1部分:入门

今天让我们来认识一下王雪琳&#xff0c;她是一位独立经营的营销咨询机构的个体企业家。在开始自己的事业之前&#xff0c;她进行了广泛的市场调研&#xff0c;明确了自己的业务定位&#xff0c;并全力以赴地投入到了自己的企业中。 一、创业背景 王雪琳的营销业务主要集中在…