【学习FreeRTOS】第8章——FreeRTOS列表和列表项

news2025/3/15 20:33:20

1.列表和列表项的简介

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

在这里插入图片描述

  • 列表相当于链表,列表项相当于节点,FreeRTOS 中的列表是一个双向环形链表
  • 列表的特点:列表项间的地址非连续的,是人为的连接到一起的。列表项的数目是由后期添加的个数决定的,随时可以改变
  • 数组的特点:数组成员地址是连续的,数组在最初确定了成员数量后期无法改变
  • 在OS中任务的数量是不确定的,并且任务状态是会发生改变的,所以非常适用列表(链表)这种数据结构

1.1.列表的数据结构

typedef struct xLIST
{
    listFIRST_LIST_INTEGRITY_CHECK_VALUE	/* 校验值 */
    volatile UBaseType_t 					uxNumberOfItems;			/* 列表中的列表项数量 */
   	ListItem_t * c							onfigLIST_VOLATILE pxIndex	/* 用于遍历列表项的指针 */
    MiniListItem_t 							xListEnd					/* 末尾列表项 */
    listSECOND_LIST_INTEGRITY_CHECK_VALUE	/* 校验值 */
} List_t;
  • 在该结构体中, 包含了两个宏,这两个宏是确定的已知常量, FreeRTOS通过检查这两个常量的值,来判断列表的数据在程序运行过程中,是否遭到破坏 ,该功能一般用于调试, 默认是不开启的
  • 成员uxNumberOfItems:用于记录列表中列表项的个数(不包含 xListEnd)
  • 成员 pxIndex:用于指向列表中的某个列表项,一般用于遍历列表中的所有列表项
  • 成员xListEnd:是一个迷你列表项,排在最末尾

1.2.列表项的数据结构

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; 	
  • xItemValue为列表项的值,这个值多用于按升序对列表中的列表项进行排序
  • pxNext 和 pxPrevious分别用于指向列表中列表项的下一个列表项和上一个列表项
  • pxOwner 用于指向包含列表项的对象(通常是任务控制块)
  • pxContainer 用于指向列表项所在列表。

1.3.迷你列表项的数据结构

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;
  • xItemValue为列表项的值,这个值多用于按升序对列表中的列表项进行排序 (一般为0xFFFFFFFF)
  • pxNext 和 pxPrevious 分别用于指向列表中列表项的下一个列表项和上一个列表项
  • 迷你列表项只用于标记列表的末尾和挂载其他插入列表中的列表项,因此不需要成员变量 pxOwner 和 pxContainer,以节省内存开销

1.4.列表、列表项、迷你列表项的关系

在这里插入图片描述
在这里插入图片描述

2.列表相关API函数介绍

2.1.初始化列表vListInitialise()

void vListInitialise( List_t * const pxList) 
{ 
	/* 初始化时,列表中只有xListEnd,因此pxIndex指向xListEnd */ 
	pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ); 
	/* xListEnd的值初始化为最大值,用于列表项升序排序时,排在最后 */
	pxList->xListEnd.xItemValue = portMAX_DELAY; 
	/* 初始化时,列表中只有xListEnd,因此上一个和下一个列表项都为xListEnd本身 */ 
	pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ); 
	pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ); 
	/*初始化时,列表中的列表项数量为0(不包含xListEnd) */ 
	pxList->uxNumberOfItems = ( UBaseType_t ) 0U; 
	/* 初始化用于检测列表数据完整性的校验值 */ 
	listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ); 
	listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); 
}
  • 形参:待初始化列表
    在这里插入图片描述

2.2.初始化列表项vListInitialiseItem()

void vListInitialiseItem(ListItem_t * const pxItem)
{
	/* 初始化时,列表项所在列表设为空 */
	pxItem->pxContainer = NULL;
	/* 初始化用于检测列表项数据完整性的校验值 */
	listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
	listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
  • 形参:待初始化列表项

2.3.列表末尾插入列表项vListInsertEnd()

void vListInsertEnd(List_t * const pxList,ListItem_t * const pxNewListItem)
{
	/* 获取列表pxIndex 指向的列表项 */
	ListItem_t * const pxIndex = pxList->pxIndex;
	/* 检查参数是否正确 */
	listTEST_LIST_INTEGRITY( pxList );
	listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
	/* 更新待插入列表项的指针成员变量 */
	pxNewListItem->pxNext = pxIndex;
	pxNewListItem->pxPrevious = pxIndex->pxPrevious;
	/* 测试使用,不用理会 */
	mtCOVERAGE_TEST_DELAY();
	/* 更新列表中原本列表项的指针成员变量 */
	pxIndex->pxPrevious->pxNext = pxNewListItem;
	pxIndex->pxPrevious = pxNewListItem;
	/* 更新待插入列表项的所在列表成员变量 */
	pxNewListItem->pxContainer = pxList;
	/* 更新列表中列表项的数量 */
	( pxList->uxNumberOfItems )++;
}
  • 形参:列表、待插入列表项
  • 此函数用于将待插入列表的列表项插入到列表 pxIndex 指针指向的列表项前面,是一种无序的插入方法
    在这里插入图片描述

2.4.列表插入列表项vListInsert()

void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem) 
{
	ListItem_t * pxIterator; 
	const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; 
	/* 检查参数是否正确 */ 
	listTEST_LIST_INTEGRITY( pxList ); 
	listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ); 
	/* 如果待插入列表项的值为最大值 */ 
	if( xValueOfInsertion == portMAX_DELAY ) { 
		/* 插入的位置为列表xListEnd前面 */ 
		pxIterator = pxList->xListEnd.pxPrevious; 
	} 
	else { 
		/* 遍历列表中的列表项,找到插入的位置 */ 
		for( 	pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); 
				pxIterator->pxNext->xItemValue <= xValueOfInsertion; 
				pxIterator = pxIterator->pxNext ) 
		{} 
	} 
	/* 将待插入的列表项插入指定位置 */ 
	pxNewListItem->pxNext = pxIterator->pxNext; 
	pxNewListItem->pxNext->pxPrevious = pxNewListItem; 
	pxNewListItem->pxPrevious = pxIterator; 
	pxIterator->pxNext = pxNewListItem; 
	/* 更新待插入列表项所在列表 */ 
	pxNewListItem->pxContainer = pxList; 
	/* 更新列表中列表项的数量 */ 
	( pxList->uxNumberOfItems )++; 
}
  • 形参:列表、待插入列表项
  • 此函数用于将待插入列表的列表项按照列表项值升序进行排序,有序地插入到列表中
    在这里插入图片描述

2.5.列表移除列表项uxListRemove()

UBaseType_t uxListRemove(ListItem_t * const pxItemToRemove)
{
	List_t * const pxList = pxItemToRemove->pxContainer;
	/* 从列表中移除列表项 */
	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
	/* 测试使用,不用理会 */
	mtCOVERAGE_TEST_DELAY();
	/* 如果pxIndex 正指向待移除的列表项 */
	if( pxList->pxIndex == pxItemToRemove ){
		/* pxIndex 指向上一个列表项 */
		pxList->pxIndex = pxItemToRemove->pxPrevious;
	}
	else{
		mtCOVERAGE_TEST_MARKER();
	}
	/* 将待移除列表项的所在列表指针清空 */
	pxItemToRemove->pxContainer = NULL;
	/* 更新列表中列表项的数量 */
	( pxList->uxNumberOfItems )--;
	/* 返回列表项移除后列表中列表项的数量 */
	return pxList->uxNumberOfItems;
}
  • 形参:待移除列表项
  • 返回值:待移除列表项移除后,所在列表剩余列表项的数量
  • 此函数用于将列表项从列表项所在列表中移除
    在这里插入图片描述

3.列表项的插入和删除实验

  • 实验目的:学会对FreeRTOS 列表和列表项的操作函数使用,并观察运行结果和理论分析是否一致
  • 实验设计:将设计三个任务:start_task、task1、task2
    start_task:用来创建其他的2个任务
    task1:实现LED0每500ms闪烁一次,用来提示系统正在运行
    task2:调用列表和列表项相关API函数,并且通过串口输出相应的信息,进行观察

在这里插入图片描述

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

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

相关文章

【大数据之Kafka】三、Kafka生产者之消息发送流程及同步异步发送API

将外部传送给过来的数据发送到kafka集群。 1 发送原理 &#xff08;1&#xff09;创建main()线程&#xff0c;创建producer对象&#xff0c;调用send方法&#xff0c;经过拦截器&#xff08;可选&#xff09;、序列化器、分区器。 &#xff08;2&#xff09;分区器将数据发送…

java面试题(16):Mysql一致性视图是啥时候建立的

1 演示错误案例 先给大家来一个错误演示。 我们打开两个会话窗口&#xff0c;默认情况下隔离级别是可重复读&#xff0c;我们来看下&#xff1a; 首先在 A 会话中查看当前 user 表&#xff0c;查看完成后开启事务&#xff1a; 可以看到id3的数据sex是男。 接下来在 B 会话中…

场景入门12----关卡切换和流送

在游戏时往往需要切换关卡&#xff0c;有两种方法&#xff0c;关卡切换和推送。关卡切换的方法是进入了一个新的地图&#xff0c;这时人物的值都复原了&#xff0c;一般都是在一个地图上推送关卡。 关卡切换 首先&#xff0c;文件新建一个新关卡&#xff0c;命名。找到之前制…

地址解析协议-ARP

ARP协议 无论网络层使用何种协议&#xff0c;在实际网络的链路上传输数据帧时&#xff0c;最终必须使用硬件地址 地址解析协议&#xff08;Address Resolution Protocol&#xff0c;ARP&#xff09;&#xff1a;完成IP地址到MAC地址的映射&#xff0c;每个主机都有一个ARP高速缓…

C语言刷题训练DAY.4

1.计算体重指数 解题思路&#xff1a; 这里我们只需要按照他的要求写出公式。 注意&#xff1a;身高要换算成米&#xff0c;打印的结构是个浮点数&#xff0c;打印的格式要相对应 解题代码&#xff1a; #include<stdio.h> int main() {int weight 0;int height 0;…

Python自动化小技巧18——自动化资产月报(word设置字体表格样式,查找替换文字)

案例背景 每月都要写各种月报&#xff0c;经营管理月报&#xff0c;资产月报.....这些报告文字目标都是高度相似的&#xff0c;只是需要替换为每个月的实际数据就行&#xff0c;如下&#xff1a; (打码是怕信息泄露.....) 可以看到&#xff0c;这个报告的都是高度模板化&…

浏览器 - 事件循环机制详解

目录 1&#xff0c;浏览器进程模型进程线程浏览器的进程和线程1&#xff0c;浏览器进程2&#xff0c;网络进程3&#xff0c;渲染进程 2&#xff0c;渲染主线程事件循环异步同步 JS 为什么会阻塞渲染任务优先级 3&#xff0c;常见面试题1&#xff0c;如何理解 js 的异步2&#x…

时序预测 | MATLAB实现基于KNN K近邻的时间序列预测-递归预测未来(多指标评价)

时序预测 | MATLAB实现基于KNN K近邻的时间序列预测-递归预测未来(多指标评价) 目录 时序预测 | MATLAB实现基于KNN K近邻的时间序列预测-递归预测未来(多指标评价)预测结果基本介绍程序设计参考资料 预测结果 基本介绍 基于KNN K近邻的时间序列预测-递归预测未来(多指标评价) …

数据集成与流动优化:解锁企业数据的无限潜力

在当今数字化时代&#xff0c;企业拥有海量数据&#xff0c;这些数据散落在不同部门、系统和平台之间&#xff0c;形成了所谓的“数据孤岛”。要想实现数据的最大化价值&#xff0c;就必须解决数据集成与流动的挑战。本文将深入探讨数据集成与流动优化的重要性&#xff0c;以及…

833-字符串中查找与替换

题目描述&#xff1a; 你会得到一个字符串 s (索引从 0 开始)&#xff0c;你必须对它执行 k 个替换操作。替换操作以三个长度均为 k 的并行数组给出&#xff1a;indices, sources, targets。 要完成第 i 个替换操作: 检查 子字符串 sources[i] 是否出现在 原字符串 s 的索…

POSTGRESQL 关于安装中自动启动的问题 详解

开头还是介绍一下群&#xff0c;如果感兴趣Polardb ,mongodb ,MySQL ,Postgresql ,redis &#xff0c;SQL SERVER ,ORACLE,Oceanbase 等有问题&#xff0c;有需求都可以加群群内有各大数据库行业大咖&#xff0c;CTO&#xff0c;可以解决你的问题。加群请加 liuaustin3微信号 &…

使用SpringBoot + Thymeleaf 完成简单的用户登录

&#x1f600;前言 本篇博文是关于Thymeleaf 的综合案例&#xff0c; 使用SpringBoot Thymeleaf 完成简单的用户登录-列表功能&#xff0c;希望你能够喜欢&#x1f60a; &#x1f3e0;个人主页&#xff1a;晨犀主页 &#x1f9d1;个人简介&#xff1a;大家好&#xff0c;我是晨…

数据结构--最短路径 Floyd算法

数据结构–最短路径 Floyd算法 F l o y d 算法&#xff1a;求出每⼀对顶点之间的最短路径 \color{red}Floyd算法&#xff1a;求出每⼀对顶点之间的最短路径 Floyd算法&#xff1a;求出每⼀对顶点之间的最短路径 使⽤动态规划思想&#xff0c;将问题的求解分为多个阶段 对于n个顶…

re学习(31)BUUCTF-xx(多层加密)

参考文章&#xff1a;【BUUCTF逆向 [2019红帽杯]xx】_nb_What_DG的博客-CSDN博客 re学习笔记&#xff08;26&#xff09;BUUCTF-re-[2019红帽杯]xx_Forgo7ten的博客-CSDN博客 还有B站 水番正文 IDA64位载入 shiftF12查看字符串 交叉引用找到关键代码 使用findcrypt插件找到…

H13-922题库 HCIP-GaussDB-OLAP V1.5

**H13-922 V1.5 GaussDB(DWS) OLAP题库 华为认证GaussDB OLAP数据库高级工程师HCIP-GaussDB-OLAP V1.0自2019年10月18日起&#xff0c;正式在中国区发布。当前版本V1.5 考试前提&#xff1a; 掌握基本的数据库基础知识、掌握数据仓库运维的基础知识、掌握基本Linux运维知识、…

互联网发展历程:速度与效率,交换机的登场

互联网的演进就像一场追求速度与效率的竞赛&#xff0c;每一次的技术升级都为我们带来更快、更高效的网络体验。然而&#xff0c;在网络的初期阶段&#xff0c;人们面临着数据传输速度不够快的问题。一项关键的技术应运而生&#xff0c;那就是“交换机”。 速度不足的困境&…

SpringBoot + Mybatis多数据源

一、配置文件 spring: # datasource: # username: root # password: 123456 # url: jdbc:mysql://127.0.0.1:3306/jun01?characterEncodingutf-8&serverTimezoneUTC # driver-class-name: com.mysql.cj.jdbc.Driverdatasource:# 数据源1onedata:jdbc-url: j…

希尔排序【Java算法】

文章目录 1. 概念2. 思路3. 代码实现 1. 概念 希尔排序也是一种插入排序&#xff0c;它是简单插入排序经过改进之后的一个更高效的版本&#xff0c;也称为缩小增量排序。希尔排序在数组中采用跳跃式分组的策略&#xff0c;通过某个增量将数组元素划分为若干组&#xff0c;然后分…

linux学习(自写shell)[11]

打印出提示信息获取用户键盘输入 cmd_line[NUM];用来保存完整的命令行 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/wait.h>#define NUM 1024 char cmd_line[NUM]; //shell int main() {wh…

AI Chat 设计模式:15. 桥接模式

本文是该系列的第十五篇&#xff0c;采用问答式的方式展开&#xff0c;问题由我提出&#xff0c;答案由 Chat AI 作出&#xff0c;灰色背景的文字则主要是我的一些思考和补充。 问题列表 Q.1 如果你是第一次接触桥接模式&#xff0c;那么你会有哪些疑问呢&#xff1f;A.1Q.2 什…