FreeRTOS(四)FreeRTOS列表与列表项

目录

列表

列表项

迷你列表项

 列表和列表项的关系

列表相关API函数

列表初始化 

列表项初始化

列表项插入

 列表项末尾插入

 列表项删除

列表遍历 


在 FreeRTOS 中,列表(List)和列表项(ListItem)是核心数据结构,用于实现任务、队列、信号量等的管理和调度。这些数据结构是 FreeRTOS 实现其调度算法和同步机制的基础。

列表是 FreeRTOS 中的一个数据结构,概念上和链表有点类似,列表被用来跟踪 FreeRTOS中的任务。

列表项就是存放在列表中的项目

列表相当于链表,列表项相当于节点,FreeRTOS 中的列表是一个双向环形链表

列表

列表是由多个列表项组成的集合,用于管理一组实体。列表提供了添加、移除、遍历列表项的操作。 (任务状态随时会发生改变)

typedef struct xLIST
{listFIRST_LIST_INTEGRITY_CHECK_VALUE		/* 校验值 */volatile UBaseType_t uxNumberOfItems;			/* 列表中的列表项数量 */ListItem_t * configLIST_VOLATILE pxIndex		/* 用于遍历列表项的指针 */MiniListItem_t xListEnd					/* 末尾列表项 */listSECOND_LIST_INTEGRITY_CHECK_VALUE		/* 校验值 */
} List_t;

1、在该结构体中, 包含了两个宏,这两个宏是确定的已知常量, FreeRTOS通过检查这两个常量的值,来判断列表的数据在程序运行过程中,是否遭到破坏 ,该功能一般用于调试, 默认是不开启的

2、成员uxNumberOfItems,用于记录列表中列表项的个数(不包含 xListEnd

3、成员 pxIndex 用于指向列表中的某个列表项,一般用于遍历列表中的所有列表项

4、成员变量 xListEnd 是一个迷你列表项,排在最末尾(这是一个特殊的列表项,用作列表的末尾标记。它通常不用于存储实际的数据,而是用来优化列表的遍历操作。xListEnd 列表项通常被插入到列表的末尾,使得在列表末尾插入和删除操作更加高效)

列表项

列表项(地址非连续、人为连接在一起的)是构成列表的基本单元,每个列表项代表了系统中的一个实体,如任务控制块(TCB)、队列、信号量等。

struct xLIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE			/* 用于检测列表项的数据完整性 */configLIST_VOLATILE TickType_t xItemValue				/* 列表项的值 */struct xLIST_ITEM * configLIST_VOLATILE pxNext		/* 下一个列表项 */struct xLIST_ITEM * configLIST_VOLATILE pxPrevious		/* 上一个列表项 */void * pvOwner							/* 列表项的拥有者 */struct xLIST * configLIST_VOLATILE pxContainer; 			/* 列表项所在列表 */listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE			/* 用于检测列表项的数据完整性 */
};
typedef struct xLIST_ITEM ListItem_t; 

 1、成员变量 xItemValue 为列表项的值,这个值多用于按升序对列表中的列表项进行排序(通常用于表示列表项的优先级或者用于在有序列表中排序。在任务的列表项中,这个值通常是任务的优先级)譬如:A列表项作业时间是10ms B列表项的作业时间是20ms,则排列顺序是A-->B,像短作业优先调度算法一样

2、成员变量 pxNext pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项

3、成员变量 pxOwner 用于指向包含列表项的对象(通常是任务控制块)

4、成员变量 pxContainer 用于指向列表项所在列表。

 

迷你列表项

 迷你列表项也是列表项,但迷你列表项仅用于标记列表的末尾和挂载其他插入列表中的列表项

它通常不用于存储实际的数据,而是用来优化列表的遍历操作。xListEnd 列表项通常被插入到列表的末尾,使得在列表末尾插入和删除操作更加高效

struct xMINI_LIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE 			/* 用于检测数据完整性 */configLIST_VOLATILE TickType_t xItemValue;				/* 列表项的值 */struct xLIST_ITEM * configLIST_VOLATILE pxNext;		/* 上一个列表项 */struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; 		/* 下一个列表项 */
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;

1、成员变量 xItemValue 为列表项的值,这个值多用于按升序对列表中的列表项进行排序

2、成员变量 pxNext pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项

3、迷你列表项只用于标记列表的末尾和挂载其他插入列表中的列表项,因此不需要成员变量 pxOwner pxContainer,以节省内存开销

 列表和列表项的关系

列表初始状态,以及即将插入的两个列表项如下(根据尾插法插入新的列表项)

列表相关API函数

列表初始化 

void vListInitialise( List_t * const pxList ) 
{ pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); (1)   pxList->xListEnd.xItemValue = portMAX_DELAY;     (2)   pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );  (3)   pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );  (4)   pxList->uxNumberOfItems = ( UBaseType_t ) 0U;     (5)   listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );   (6)   listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );   (7)   }

(1)这行代码设置 pxIndex 成员,这是一个用于快速索引的指针,它指向列表的末尾。xListEnd 是一个 MiniListItem_t 类型的成员,它作为一个哨兵节点,表示列表的末尾。这样做的目的是为了优化列表的操作,使得在列表末尾插入和删除操作更加高效。

(2)这里将列表结束节点的 xItemValue 设置为 portMAX_DELAYportMAX_DELAY 是一个定义在 FreeRTOS 配置文件中的常量,代表最大的延迟时间。在列表中,它通常用来表示列表项的最大优先级值,用于有序列表的末端。

(3)  pxNext 成员指向下一个列表项。在列表初始化时,列表为空,所以末尾节点的 pxNext 指针指向它自己本身,表示没有更多的元素。

(4)   pxPrevious 成员指向前一个列表项。同样地,初始化时列表为空,所以末尾节点的 pxPrevious 指针也指向它自己本身。

(5)   uxNumberOfItems 成员记录列表中当前的列表项数量。在列表初始化时,列表为空,所以这个值被设置为 0

(6)   listSET_LIST_INTEGRITY_CHECK_1_VALUE 宏用于设置列表的第一个完整性检查值。这是 FreeRTOS 的一种机制,用于在运行时检查列表的完整性是否遭到破坏。如果内存被意外修改,这些值将会改变,从而可以检测到错误。

(7)   listSET_LIST_INTEGRITY_CHECK_2_VALUE 宏用于设置列表的第二个完整性检查值。与第一个检查值一样,它提供了额外的一层保护,以确保列表数据结构没有被损坏

列表项初始化

void vListInitialiseItem( ListItem_t * const pxItem ) 
{ pxItem->pvContainer = NULL;     (1)listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); (2)listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem ); (3)
}

(1)这行代码将列表项的 pvContainer 成员初始化为 NULLpvContainer 是一个空指针,用于指向包含该列表项的列表。当列表项没有被包含在任何列表中时,它的 pvContainerNULL。当列表项被添加到列表中时,它的 pvContainer 会被设置为指向该列表。

(2)和(3)

这两行代码用于设置列表项的完整性检查值。这是 FreeRTOS 的一种机制,用于在运行时检查列表项的完整性是否遭到破坏。如果内存被意外修改,这些值将会改变,从而可以检测到错误。

  • listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE:宏用于设置列表项的第一个完整性检查值。
  • listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE:宏用于设置列表项的第二个完整性检查值。

列表项插入

void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) 
{ ListItem_t *pxIterator; const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;   (1) listTEST_LIST_INTEGRITY( pxList );        (2) listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); if( xValueOfInsertion == portMAX_DELAY )       (3) { pxIterator = pxList->xListEnd.pxPrevious;       (4) } else { for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->\  (5) pxNext->xItemValue <=xValueOfInsertion; pxIterator = pxIterator->pxNext )  { //空循环,什么也不做! } }  pxNewListItem->pxNext = pxIterator->pxNext;       (6) pxNewListItem->pxNext->pxPrevious = pxNewListItem; pxNewListItem->pxPrevious = pxIterator; pxIterator->pxNext = pxNewListItem; pxNewListItem->pvContainer = ( void * ) pxList;       (7) ( pxList->uxNumberOfItems )++;          (8) 
}

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

(2)、这一行和下一行代码用来检查列表和列表项的完整性的。其实就是检查列表和列表项中用于完整性检查的变量值是否被改变。这些变量的值在列表和列表项初始化的时候就被写入 了,这两行代码需要实现函数configASSERT()!

(3)、要插入列表项,第一步就是要获取该列表项要插入到什么位置!如果要插入的列表项 的值等于portMAX_DELAY,也就是说列表项值为最大值,这种情况最好办了,要插入的位置 就是列表最末尾了。

(4)、获取要插入点,注意!列表中的 xListEnd 用来表示列表末尾,在初始化列表的时候 xListEnd的列表值也是portMAX_DELAY,此时要插入的列表项的列表值也是portMAX_DELAY。 这两个的顺序该怎么放啊?通过这行代码可以看出要插入的列表项会被放到xListEnd前面。

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

(6)、经过上面的查找,我们已经找到列表项的插入点了,从本行开始接下来的四行代码就 是将列表项插入到列表中,插入过程和数据结构中双向链表的插入类似。像 FreeRTOS 这种 RTOS 系统和一些协议栈都会大量用到数据结构的知识,所以建议大家没事的时候多看看数据 结构方面的书籍,否则的话看源码会很吃力的。

(7)、列表项已经插入到列表中了,那么列表项的成员变量 pvContainer 也该记录此列表项 属于哪个列表的了。

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

 列表项末尾插入

void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) 
{ ListItem_t * const pxIndex = pxList->pxIndex; listTEST_LIST_INTEGRITY( pxList );       (1)listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );  pxNewListItem->pxNext = pxIndex;        (2) pxNewListItem->pxPrevious = pxIndex->pxPrevious; mtCOVERAGE_TEST_DELAY(); pxIndex->pxPrevious->pxNext = pxNewListItem; pxIndex->pxPrevious = pxNewListItem; pxNewListItem->pvContainer = ( void * ) pxList;     (3) ( pxList->uxNumberOfItems )++;          (4)}

(1)、与下面的一行代码完成对列表和列表项的完整性检查。

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

(3)、标记新的列表项pxNewListItem属于列表pxList。

(4)、记录列表中的列表项数目的变量加一,更新列表项数目。

 列表项删除

UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) 
{ List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;   (1) pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious; (2) pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; mtCOVERAGE_TEST_DELAY();  if( pxList->pxIndex == pxItemToRemove )         { pxList->pxIndex = pxItemToRemove->pxPrevious;     (3) } else { mtCOVERAGE_TEST_MARKER(); }  pxItemToRemove->pvContainer = NULL;        (4) ( pxList->uxNumberOfItems )--; return pxList->uxNumberOfItems;          (5) 
}

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

(2)、与下面一行完成列表项的删除,其实就是将要删除的列表项的前后两个列表项“连接” 在一起。

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

(4)、被删除列表项的成员变量pvContainer清零。

(5)、返回新列表的当前列表项数目。

列表遍历 

#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )      (1) 
{                  \  List_t * const pxConstList = ( pxList );           ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;      (2) if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd )(3)     {                  ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;     (4) }                 ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;        (5)
}

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

(2)、列表的pxIndex 变量指向下一个列表项。

(3)、如果pxIndex 指向了列表的xListEnd成员变量,表示到了列表末尾。

(4)、如果到了列表末尾的话就跳过 xListEnd,pxIndex 再一次重新指向处于列表头的列表 项,这样就完成了一次对列表的遍历。

(5)、将pxIndex 所指向的新列表项的pvOwner赋值给pxTCB。 此函数用于从多个同优先级的就绪任务中查找下一个要运行的任务。

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

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

相关文章

Centos7系统根分区空间小home空间大如何增加分区

Centos7 默认安装&#xff0c;区划默认划分&#xff0c;用着怎么感觉有问题&#xff0c;根分区太小50G&#xff0c;而home分区太大。 如果处理&#xff0c;能扩大根分区呢&#xff1f;如果是新安装的&#xff0c;可以先删除home&#xff0c;然后再扩容 根分区。最后使其生效。…

计算机视觉硬件整理(四):相机与镜头参数介绍

文章目录 前言一、工业相机常用分类二、工业相机的基本参数三、工业相机的接口四、工业镜头的参数五、工业镜头的选择要点 前言 随着科技的飞速发展&#xff0c;工业自动化和智能制造在当今社会扮演着越来越重要的角色。在这个背景下&#xff0c;工业相机作为一种关键的视觉检…

Qualitor processVariavel.php 未授权命令注入漏洞复现(CVE-2023-47253)

0x01 漏洞概述 Qualitor 8.20及之前版本存在命令注入漏洞,远程攻击者可利用该漏洞通过PHP代码执行任意代码。 0x02 复现环境 FOFA&#xff1a;app"Qualitor-Web" 0x03 漏洞复现 PoC GET /html/ad/adpesquisasql/request/processVariavel.php?gridValoresPopHi…

【azure-openai】批量翻译demo【python】【gradio】

要求&#xff1a;拥有azure-openai-api&#xff0c;上传文件为csv格式&#xff0c;utf-8编码。 注意&#xff1a;如果出现乱码&#xff0c;重新运行&#xff0c;换种方式打开&#xff0c;有时候wps会自动改编码。 实现功能&#xff1a;选择语言&#xff0c;使用gpt4omini&…

使用docker形式部署prometheus+alertmanager+钉钉告警

一、拉取所需要的镜像 docker pull prom/node-exporter docker pull grafana/grafana docker pull prom/prometheus docker pull prom/alertmanager 其中 prom/node-exporter&#xff1a;用于收集主机系统信息和指标的 grafana/grafana&#xff1a;是一个用于可视化和分…

mac 上配置Jmeter代理进行web脚本录制过程容易踩坑的点

macOS 配置 Jmeter代理录制web脚本&容易踩坑的点 mac配置下载&#xff1a;前景提要&#xff1a;Jmeter中具体操作容易踩坑的点1、进入浏览器后&#xff0c;显示访问连接不安全。2、证书失效需要重新生成3、重新生成证书的方式4、没有生成新的证书5、jmeter安装路径找不到 m…

硬件设计很简单?合宙低功耗4G模组Air780E—开机启动及外围电路设计

Air780E是合宙低功耗4G-Cat.1模组经典型号之一&#xff0c;上期我们解答了大家关心的系列问题&#xff0c;并讲解了选型的注意要点。 有朋友问&#xff1a;能不能讲些硬件设计相关的内容&#xff1f; 模组的上电开机&#xff0c;是硬件设计调试的第一步。 本期特别分享——Ai…

MySQL数据库进阶知识(五)《锁》

学习目标&#xff1a; 一周掌握数据库锁相关知识 学习内容&#xff1a; 一. 概述 介绍 锁是计算机协调多个进程或线程并发访问某一资源的机制。在数据库中&#xff0c;除传统的计算资源&#xff08;CPU、RAM、I/O&#xff09;的争用以外&#xff0c;数据也是一种供许多用户共…

将本地文件上传至虚拟机

1、查看虚拟机ip地址 ip addr 2、xshell连接上虚拟机 连接root连接不上的解决办法更改配置文件vim /etc/ssh/sshd_config 重启&#xff08;sudo service ssh restart&#xff09;并查看是否开启ssh服务&#xff08;sudo ps -e | grep ssh&#xff09; 即可连接成功 3、复制文…

在实时语音交互上超过GPT-4o,端到端语音模型Mini-Omni部署

Mini-Omni是清华大学开源的多模态大型语言模型&#xff0c;具备实时语音输入和流式音频输出的能力。 Mini-Omni模型能够一边听、一边说&#xff0c;一边思考&#xff0c;类似于ChatGPT的语言对话模式。 Mini-Omni模型的主要特点是能够直接通过音频模态进行推理&#xff0c;并…

Skywalking告警配置

背景 skywalking 9.7.0&#xff0c;地址&#xff1a;Backend setup | Apache SkyWalking helm&#xff1a;skywalking-helm:4.5.0&#xff0c;地址&#xff1a;skywalking-helm/chart/skywalking/values.yaml at v4.5.0 首先来说一下为什么使用skywalking告警&#xff1f; …

JS设计模式之组合模式:打造灵活高效的对象层次结构

引言 当我们构建复杂的应用程序时&#xff0c;经常会遇到处理对象层次结构的情况。这些层次结构通常是树形结构&#xff0c;由组合节点和叶子节点组成。在这样的情况下&#xff0c;JavaScript 设计模式之一的组合模式就能派上用场。 组合模式是一种结构型设计模式&#xff0c…

MySQL从入门到精通 - 基础篇

一、MySQL概述 1. 数据库相关概念 二、SQL &#xff08;1&#xff09;SQL通用语法 &#xff08;2&#xff09;SQL分类 &#xff08;3&#xff09;数据定义语言DDL 数据库操作 表操作 数据类型 1. 数值类型 2. 字符串类型 二进制数据&#xff1a;以二进制格式&#xff08;0和…

【JavaEE初阶】深入解析死锁的产生和避免以及内存不可见问题

前言&#xff1a; &#x1f308;上期博客&#xff1a;【后端开发】JavaEE初阶—线程安全问题与加锁原理&#xff08;超详解&#xff09;-CSDN博客 &#x1f525;感兴趣的小伙伴看一看小编主页&#xff1a;GGBondlctrl-CSDN博客 ⭐️小编会在后端开发的学习中不断更新~~~ &#…

C#图像处理学习笔记(屏幕截取,打开保存图像、旋转图像、黑白、马赛克、降低亮度、浮雕)

1、创建Form窗体应用程序 打开VS&#xff0c;创建新项目-语言选择C#-Window窗体应用&#xff08;.NET Framework) 如果找不到&#xff0c;检查一下有没有安装.NET 桌面开发模块&#xff0c;如果没有&#xff0c;需要下载&#xff0c;记得勾选相关开发工具 接上一步&#xff0c;…

【UE5】将2D切片图渲染为体积纹理,最终实现使用RT实时绘制体积纹理【第四篇-着色器投影-接收阴影部分】

上一章中实现了体积渲染的光照与自阴影&#xff0c;那我们这篇来实现投影 回顾 勘误 在开始本篇内容之前&#xff0c;我已经对上一章中的内容的错误进行了修改。为了确保不会错过这些更正&#xff0c;同时也避免大家重新阅读一遍&#xff0c;我将在这里为大家演示一下修改的…

叉车司机信息权限采集系统,保障与优化叉车运输网络的安全

叉车司机信息权限采集系统可以通过监控司机的行车行为和车辆状况&#xff0c;实时掌握车辆位置和行驶路线&#xff0c;从而提高运输安全性&#xff0c;优化运输网络&#xff0c;降低事故风险。同时&#xff0c;该系统还可以通过对叉车司机信息和行车数据的分析&#xff0c;优化…

Flutter屏幕适配

我们可以根据下面有适配属性的Widget来进行屏幕适配 1.MediaQuery 通过它可以直接获得屏幕的大小&#xff08;宽度 / 高度&#xff09;和方向&#xff08;纵向 / 横向&#xff09; Size screenSize MediaQuery.of(context).size; double width screenSize.width; double h…

springboot异常(三):异常处理原理

&#x1f345;一、BasicErrorController ☘️1.1 描述 BasicErrorController是Springboot中默认的异常处理方法&#xff0c;无需额外的操作&#xff0c;当程序发生了异常之后&#xff0c;Springboot自动捕获异常&#xff0c;重新请求到BasicErrorController中&#xff0c;在B…

网络安全 DVWA通关指南 DVWA Stored Cross Site Scripting (存储型 XSS)

DVWA Stored Cross Site Scripting (存储型 XSS) 文章目录 DVWA Stored Cross Site Scripting (存储型 XSS)XSS跨站原理存储型 LowMediumHighImpossible 参考文献 WEB 安全靶场通关指南 相关阅读 Brute Force (爆破) Command Injection&#xff08;命令注入&#xff09; Cro…