FreeRTOS的列表与列表项

目录

1.为什么要学列表?

2.什么是列表和列表项?

2.1 列表

2.2列表项

 2.3,迷你列表项

3.列表与列表项的初始化

3.1 列表初始化

 3.2列表项初始化

4.列表项的“增删查”(插入、删除、遍历)

4.1列表项的插入

4.1.1普通插入vListInsert()

4.1.2列表项末尾插入vListInsertEnd()

4.2 列表项的删除

4.3列表的遍历

总结:


1.为什么要学列表?

        要想看懂 FreeRTOS 源码并学习其原理,有一个东西绝对跑不了,那就是 FreeRTOS 的列表和列表项。列表和列表项是FreeRTOS的一个数据结构,FreeRTOS 大量使用到了列表和列表项,它是 FreeRTOS 的基石。要想深入学习并理解 FreeRTOS,那么列表和列表项就必须首先掌握,否则后面根本就没法进行。

2.什么是列表和列表项?

2.1 列表

列表是 FreeRTOS 中的一个数据结构,概念上和链表有点类似,列表被用来跟踪 FreeRTOS 中的任务。与列表相关的全部东西都在文件 list.c list.h 中。在 list.h 中定义了一个叫 List_t 的结构体,代码如下:

代码可能有些难以理解,下面是容易理解的列表图:

其中:

uxNumberOfItems 用来记录列表中列表项的数量

pxIndex 用来记录当前列表项索引号,用于遍历列表

       列表中最后一个列表项xListEnd,用来表示列表结束,此变量类型为 MiniListItem_t,这是一个迷你列表项。

注意!此图只是主要列表成员变量。

2.2列表项

        列表项就是存放在列表中的项目,FreeRTOS 提供了两种列表项:列表项和迷你列表项。这

两个都在文件 list.h 中有定义,定义如下:

 

同样,下面是容易理解的列表项图:

xItemValue 为列表项值

pxNext 指向下一个列表项

pxPrevious 指向前一个列表项,和 pxNext 配合起来实现类似双向链表的功能

pvOwner 记录此链表项归谁拥有,通常是任务控制块

pvContainer 用来记录此列表项归哪个列表。注意和 pvOwner 的区别,在前面讲解任务

控制块 TCB_t 的时候说了在 TCB_t 中有两个变量 xStateListItem 和 xEventListItem,这两个变量的类型就是 ListItem_t,也就是说这两个成员变量都是列表项。以xStateListItem 为例,当创建一个任务以后 xStateListItem 的 pvOwner 变量就指向这个任务的任务控制块,表示 xSateListItem 属于此任务。当任务就绪态以后 xStateListItem 的变量 pvContainer 就指向就绪列表,表明此列表项在就绪列表中。举个通俗一点的例子:小王在上二年级,他的父亲是老王。如果把小王比作列表项,那么小王的 pvOwner 属性值就是老王,小王的 pvContainer 属性值就是二年级。

注意!此图也只是主要列表成员变量。

 2.3,迷你列表项

上面我们我们说了列表项,现在来看一下迷你列表项,迷你列表项在文件 list.h 中有定义,

如下:

 同上,迷你列表项图如下:

3.列表与列表项的初始化

3.1 列表初始化

新创建或者定义的列表需要对其做初始化处理,列表的初始化其实就是初始化列表结构体 List_t 中的各个成员变量,列表的初始化通过使函数 vListInitialise()来完成,此函数在 list.c 中有定义,函数如下:

        xListEnd 用来表示列表的末尾,而 pxIndex 表示列表项的索引号,此时列表只有一个列表项,那就是 xListEnd,所以 pxIndex 指向 xListEnd。

      xListEnd 的列表项值初始化为 portMAX_DELAYportMAX_DELAY 是个宏,在文件portmacro.h 中有定义。根据所使用的 MCU 的不同,portMAX_DELAY 值也不相同,可以为 0xffff

     初始化列表项 xListEnd pxNext 变量,因为此时列表只有一个列表项 xListEnd,因此 pxNext 只能指向自身。

    初始化 xListEnd pxPrevious 变量,也指向 xListEnd 自身。

    由于此时没有其他的列表项,因此 uxNumberOfItems 0,注意,这里没有算 xListEnd。初始化列表项中用于完整性检查字段,只有宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 1 的时候才有效。同样的根据所选的MCU 不同其写入的值也不同,可以为 0x5a5a 或者 0x5a5a5a5aULSTM32 32 位系统写入的是 0x5a5a5a5aUL,或者 0xffffffffUL,本文中为 0xffffffffUL

下面是相应列表初始化图:

 3.2列表项初始化

同列表一样,列表项在使用的时候也需要初始化,列表项初始化由函数 vListInitialiseItem()

来完成,函数如下:

       列表项的初始化很简单,只是将列表项成员变量 pvContainer 初始化为 NULL,并且给用于完整性检查的变量赋值。有朋友可能会问,列表项的成员变量比列表要多,怎么初始化函数就这么短?其他的成员变量什么时候初始化呢?这是因为列表项要根据实际使用情况来初始化,比如任务创建函数 xTaskCreate()就会对任务堆栈中的 xStateListItem xEventListItem 这两个列表项中的其他成员变量在做初始化,任务创建过程后面会详细说明。

4.列表项的“增删查”(插入、删除、遍历)

4.1列表项的插入

列表项有两种插入方式,普通插入与末尾插入。

4.1.1普通插入vListInsert()

下面首先来讲普通插入,它通过函数 vListInsert()来完成,函数原型如下:

其中:

pxList:列表项要插入的列表。

pxNewListItem: 要插入的列表项。

函数 vListInsert()的参数 pxList 决定了列表项要插入到哪个列表中,pxNewListItem 决定了

要插入的列表项,但是这个列表项具体插入到什么地方呢?要插入的位置由列表项中成员变量xItemValue 来决定。列表项的插入根据 xItemValue 的值按照升序的方式排列!接下来我们来具体看一下函数 vListInsert()的整个运行过程,函数代码如下:

 我总结一下该代码的逻辑,

       首先是获取要插入的列表项值,即列表项成员变量 xItemValue 的值,因为要根据这个值来确定列表项要插入的位置。

       其次检查列表和列表项的完整性。

      再然后获取该列表项要插入到什么位置!如果要插入的列表项的值等于portMAX_DELAY,也就是说列表项值为最大值,要插入的位置就是列表最末尾。

      之后获取要插入点,注意!插入的列表项会被放到 xListEnd 前面。

      如果要插入的列表项的值如果不等于 portMAX_DELAY 那么就需要在列表中一个一个的找自己的位置,这个 for 循环就是找位置的过程,当找到合适列表项的位置的时候就会跳出。由于这个 for 循环是用来寻找列表项插入点的,所以 for 循环体里面没有任何东西。这个查找过程是按照升序的方式查找列表项插入点的。

      获取插入点之后,将列表项插入到列表中,如图(6)中的四行,插入过程和数据结构中双向链表的插入类似。

    列表项的成员变量 pvContainer 记录此列表项属于哪个列表的。

    列表的成员变量 uxNumberOfItems 加一,表示又添加了一个列表项。

普通插入是按插入值以升序的方式插入的,若从头先插入40插入值的列表项,如下图:

之后插入60插入值的列表项:

再插入一个50插入值的列表项:

4.1.2列表项末尾插入vListInsertEnd()

列表末尾插入列表项的操作通过函数 vListInsertEnd ()来完成,函数原型如下:

参数:

pxList:列表项要插入的列表。

pxNewListItem: 要插入的列表项。

函数 vListInsertEnd()源码如下:

        它与vListInsert()的区别在于,函数vListInsert()向列表中插入一个列表项的时候这个列表项的位置是通过列表项的值,也就是列表项成员变量 xItemValue 来确定。vListInsertEnd()是往列表的末尾添加列表项的,我们知道列表中的 xListEnd 成员变量表示列表末尾的,那么函数 vListInsertEnd()插入一个列表项是不是就是插到 xListEnd 的前面或后面啊?这个是不一定的,这里所谓的末尾要根据列表的成员变量pxIndex 来确定的!前面说了列表中的 pxIndex 成员变量是用来遍历列表的,pxIndex 所指向的列表项就是要遍历的开始列表项,也就是说 pxIndex 所指向的列表项就代表列表头!由于是个环形列表,所以新的列表项就应该插入到 pxIndex 所指向的列表项的前面。

      标记新的列表项 pxNewListItem 属于列表 pxList

列表项末尾插入图示:

我们先准备一个默认列表,如下图:

在40与60的插入值里插入50的列表项。

列表 List pxIndex 指向列表项 ListItem1,因此调用函数 vListInsertEnd()插入 ListItem3 的话就会在 ListItem1 的前面插入。

4.2 列表项的删除

有列表项的插入,那么必然有列表项的删除,列表项的删除通过函数 uxListRemove()来完成,函数原型如下:

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )

参数:

pxItemToRemove:要删除的列表项。

返回值:

返回删除列表项以后的列表剩余列表项数目。

注意,列表项的删除只是将指定的列表项从列表中删除掉,并不会将这个列表项的内存给

释放掉!如果这个列表项是动态分配内存的话。

函数 uxListRemove()的源码如下:

       首先,要删除一个列表项我们得先知道这个列表项处于哪个列表中,读取列表项中的成员变量 pvContainer 就可以得到此列表项处于哪个列表中,所以直接读取

       将要删除的列表项的前后两个列表项“连接”在一起完成列表项的删除

       如果列表的 pxIndex 正好指向要删除的列表项,那么在删除列表项以后要重新给pxIndex 找个“对象”,这个新的对象就是被删除的列表项的前一个列表项。

       把被删除列表项的成员变量 pvContainer 清零。

       返回新列表的当前列表项数目。

4.3列表的遍历

        介绍列表结构体的时候说过列表 List_t 中的成员变量 pxIndex 是用来遍历列表的,FreeRTOS 提供了一个函数来完成列表的遍历,这个函数是 listGET_OWNER_OF_NEXT_ENTRY()。每调用一次这个函数列表的 pxIndex 变量就会指向下一个列表项,并且返回这个列表项的 pxOwner变量值。这个函数本质上是一个宏,这个宏在文件 list.h 中如下定义:

        pxTCB 用来保存 pxIndex 所指向的列表项的 pvOwner 变量值,也就是这个列表项属于谁的?通常是一个任务的任务控制块。pxList 表示要遍历的列表。

        列表的 pxIndex 变量指向下一个列表项。

        然后判断,如果 pxIndex 指向了列表的 xListEnd 成员变量,表示到了列表末尾。

        最后pxIndex 所指向的新列表项的 pvOwner 赋值给 pxTCB

此函数用于从多个同优先级的就绪任务中查找下一个要运行的任务。

总结:

          FreeRTOS的列表与列表项是我们学习并理解FreeRTOS任务控制的基础,任务创建,删除,任务的上下文切换都会有列表与列表项的参与,由此可见他们的重要性,,也希望大家看我的文章能够有所收获,早日掌握FreeRTOS!

FreeRTOS开发手册word版网盘

通过百度网盘分享的文件:STM32F1 FreeRTOS开发手册_V1.1.docx
链接:https://pan.baidu.com/s/14On7A8iwbEeLxLN2Ghb0HQ 
提取码:sxss

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

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

相关文章

前端(3)——快速入门JaveScript

参考: 罗大富 JavaScript 教程 | 菜鸟教程 JavaScript 教程 1. JaveScript JavaScript 简称 JS JavaScript 是一种轻量级、解释型、面向对象的脚本语言。它主要被设计用于在网页上实现动态效果,增加用户与网页的交互性。作为一种客户端脚本语言&#…

使用阿里云快速搭建 DataLight 平台

使用阿里云快速搭建 DataLight 平台 本篇文章由用户 “闫哥大数据” 分享,B 站账号:https://space.bilibili.com/357944741?spm_id_from333.999.0.0 注意:因每个人操作顺序可能略有区别,整个部署流程如果出现出入,以…

H.265流媒体播放器EasyPlayer.js H.264/H.265播放器chrome无法访问更私有的地址是什么原因

EasyPlayer.js H5播放器,是一款能够同时支持HTTP、HTTP-FLV、HLS(m3u8)、WS、WEBRTC、FMP4视频直播与视频点播等多种协议,支持H.264、H.265、AAC、G711A、MP3等多种音视频编码格式,支持MSE、WASM、WebCodec等多种解码方…

QT_CONFIG宏使用

时常在Qt代码中看到QT_CONFIG宏,之前以为和#define、DEFINES 差不多,看了定义才发现不是那么回事,定义如下: 看注释就知道了QT_CONFIG宏,其实是:实现了一个在编译时期安全检查,检查指定的Qt特性…

centos7安装Chrome使用selenium-wire

背景:在centos7中运行selenium-wire爬虫,系统自带的Firefox浏览器不兼容,运行报错no attribute ‘set_preference’,应该是selenium-wire和Firefox的驱动不兼容 查了半天不知道怎么解决,就想在centos7上安装Chrome来跑…

医院信息化与智能化系统(21)

医院信息化与智能化系统(21) 这里只描述对应过程,和可能遇到的问题及解决办法以及对应的参考链接,并不会直接每一步详细配置 如果你想通过文字描述或代码画流程图,可以试试PlantUML,告诉GPT你的文件结构,让他给你对应…

《FreeRTOS任务控制块篇》

Task control block, 即任务控制块。任务控制块(TCB)是一个结构体,它会分配给每个任务,其中存储着任务的状态信息,包括指向任务上下文(任务的运行时环境,包括寄存器值)的指针。任务控…

Queuing 表(buffer表)的优化实践 | OceanBase 性能优化实践

案例问题描述 该案例来自一个金融行业客户的问题:他们发现某个应用对一个数据量相对较小的表(仅包含数千条记录)访问时,频繁遇到性能下降的情况。为解决此问题,客户向我们求助进行分析。我们发现这张表有频繁的批量插…

ssh登陆服务器后支持Tab键命令补全

在服务器上新建了用户后,通过ssh登录到服务器后发现不能使用Tab键来进行命令补全 截图如下: 以为没有配置.bashrc 此时输入 source 发现无此命令 细心的可以发现 -sh 于是输入命令echo $SHELL 确认此时的shell为sh, 只要输入命令bash即可切…

[白月黑羽]关于仿写类postman功能软件题目的解答

原题: 答: python文件如下 from PySide6.QtWidgets import QApplication, QMessageBox,QTableWidgetItem,QHeaderView,QWidget,QTableWidget from PySide6.QtCore import QEvent,QObject from PySide6.QtUiTools import QUiLoader import time import …

Postman接口测试(断言、关联、参数化、输出测试报告)

基本界面展示 Get、Post请求 Postman断言 使用postman来判断预期结果与实际结果是否一致 响应状态码断言 响应包含字符串 断言判断字符串的格式 关联 用于解决http请求之间存在依赖关系 依赖:一个http请求的响应结果中的数据,被另一个请求使用 登…

【卡尔曼滤波】数据融合Fusion的应用 C语言、Python实现(Kalman Filter)

【卡尔曼滤波】数据融合Fusion的应用 C语言、Python实现(Kalman Filter) 更新以gitee为准: gitee地址 文章目录 卡尔曼滤波数据融合Python实现C语言实现多个数据如何融合附录:压缩字符串、大小端格式转换压缩字符串浮点数压缩Pac…

网络原理-网络层和数据链路层

一、网络层 1、IP协议完成的工作 地址管理:使用一套地址体系来描述所没备的位置 路由选择:一个数据包如何从网络的某个地址传到另一个地址 2、IP报头 4 位版本号:取值为4或6 (IPv4/IPv6) 4 位首部长度:IP报头,单位…

【Three.js基础学习】22.New project structure

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 前言 这里将使用全新的项目结构,将不同工具分层,区分开使用。 一、结构目录 二、对应文件 1.script.js 获取画布,引入样式和功能。 /* 课…

AI风向标|算力与通信的完美融合,SRM6690解锁端侧AI的智能密码

当前,5G技术已经成为推动数字经济和实体经济深度融合的关键驱动力,进入5G发展的下半场,5G与AI的融合正推动诸多行业的数字化转型和创新发展,终端侧AI和端云混合式AI将广泛应用于各类消费终端和各行各业。 在推动5G和AI与各行业场…

【WPF】Prism学习(二)

Prism Commands 1.命令(Commanding) 1.1. ViewModel的作用: ViewModel不仅提供在视图中显示或编辑的数据,还可能定义一个或多个用户可以执行的动作或操作。这些用户可以通过用户界面(UI)执行的动作或操作…

智慧建造-运用Trimble技术将梦幻水族馆变为现实【上海沪敖3D】

项目概述 西雅图水族馆耗资1.6亿美元对海洋馆进行扩建。该项目包括建造三个大型栖息地,每个建筑物几乎都没有直边,其中一个主栖息地由520立方米混凝土和355吨钢筋组成。特纳建筑公司的混凝土团队通过强大的贸易合作伙伴和创新的数字制造技术,…

kubesphere环境-本地Harbor仓库+k8s集群(单master 多master)+Prometheus监控平台部署

前言:半月前在公司生产环境上离线部署了k8s集群Victoria Metrics(二开版)自研版夜莺 监控平台的搭建,下面我租用3台华为云服务器演示部署kubesphere环境-本地Harbor仓库k8s集群(单master节点 & 单master节点)Prometheus监控部…

java 随机生成验证码

1.需求 实现随机生成验证码,验证码可能是大小写字母和数字 2.实现 写一个getCode方法实现 public static String getCode(int n){//1. 定义一个字符串,字符串中包含大小写字母和数字String str "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrs…

Unity图形学之Blend指令

1.渲染流程:Blend 决定了要渲染的像素和Gbuffer里像素到底怎么取舍 2.Blend 公式: 3.factor可以取值的内容有: One 1 Zero :0 SrcColor : 要渲染的像素 SrcAlpha : 要渲染像素的 a 通道。 DstColor : 已经渲染在gbuffer…