正点原子FreeRTOS学习笔记——列表与列表项

server/2024/11/13 10:46:49/

目录

一、什么是列表和列表项

1、概念

2、FreeRTOS代码

(1)列表

(2)列表项

(3)迷你列表项 

二、列表与列表项初始化

1、列表初始化

2、列表项初始化

三、列表插入与删除列表项

1、原理解释

2、升序插入列表项

3、末尾插入列表项

4、移除列表项


一、什么是列表和列表项

1、概念

在FreeRTOS中,有三个列表分别是就绪列表、阻塞列表与挂起列表。当任务状态改变就会迁移到其他列表中。

列表是一个双向环形链表,而链表是一种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 。链表可以任意的插入与删除节点,并且不限制元素的数量。

列表项是存放在列表中的项目,用来存放FreeRTOS中的任务。

以右图举例,三个人组成的整体就作为一个列表,而每个人是这个列表中的列表项。列表项之间地址是非连续,是人为的连接到一起的。是依靠列表项中的pxNext(指向下一个地址指针)、pxPrevious(指向上一个地址指针)互相连接。相当于右图中的胳膊互相拉着。     

2、FreeRTOS代码

(1)列表

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;

(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;                    

(3)迷你列表项 

struct xMINI_LIST_ITEM
{listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */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、列表初始化

#define portMAX_DELAY    ( TickType_t ) 0xffffffffUL/*形参:待初始化列表*/
void vListInitialise( List_t * const pxList ) 
{/*列表的pxIndex指向末尾列表项*/pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );/*将末尾列表项数值设为最大*/pxList->xListEnd.xItemValue = portMAX_DELAY;/*列表的末尾列表项上一个下一个都指向自己,因为初始化只有末尾列表项*/pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );     pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );/*列表中列表项个数设为0,末尾列表项不计入*/pxList->uxNumberOfItems = ( UBaseType_t ) 0U;/*检测数据完整性*/listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}

2、列表项初始化

/*形参:待初始化列表项*/
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 );
}

                                                                                                                                                            

三、列表插入与删除列表项

1、原理解释

在小红和小黑之间加入小蓝。小红的pxNext对应小黑,小黑的pxPrevious对应小红。现在小蓝加入列表之中,小红先把pxNext接上小蓝,小蓝把pxPrevious接上小红,小蓝就和小红牵上手;小黑把pxPrevious接上小蓝,小蓝又把pxNext接上小黑,小蓝就和小黑牵上手。这样小蓝这个列表项就加入到列表之中。

2、升序插入列表项

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 )//是末尾列表项{   /* 插入的位置为末尾列表项前面*/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 )++;
}

3、末尾插入列表项

形参:待插入的列表,插入列表项
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{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 )++;
}

4、移除列表项

形参:待移除的列表项
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{/* 获取所在的列表 */List_t * const pxList = pxItemToRemove->pxContainer;/* 从列表中移除列表项 */pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;/* Only used during decision coverage testing. */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;
}

                                                                                                                                                            


http://www.ppmy.cn/server/41826.html

相关文章

AD域服务器巡检指南

Active Directory (AD) 域服务器的巡检对于确保企业网络的安全性和高效运行至关重要。以下是针对AD域服务器巡检的关键活动和其重要性的优化描述&#xff1a; 保证系统安全&#xff1a; AD域服务器储存大量敏感数据&#xff0c;包括用户账户信息、策略和访问权限数据。定期巡检…

构建NFS远程共享存储

nfs-server:10.1.59.237 nfs-web:10..159.218 centos7,服务端和客户端都关闭防火墙和selinux内核防火墙&#xff0c;如果公司要求开启防火墙&#xff0c;那需要放行几个端口 firewall-cmd --add-port2049/tcp --permanent firewall-cmd --add-port111/tcp --permanent firew…

知识付费系统怎么操作的,培训机构怎么用老带新招生呢?

随着暑假竞争的日益剧烈&#xff0c;各类教育培训机构早已准备着各种招生活动&#xff0c;打算进一步进步学校的招生数量。但是也有很多招生问题在搅扰着学校的招生教师&#xff0c;其实一切的招生活动&#xff0c;都必需效劳于重生报名和老生续报!培训机构如何做好老带新招生?…

7集成学习评分卡

集成学习评分卡 学习目标 知道LightGBM基本原理掌握使用lightGBM进行特征筛选的方法1 Gradient Boosting算法回顾 Gradient Boosting 基本原理 训练一个模型m1,产生错误e1针对e1训练一个模型m2,产生错误e2针对e2训练第三个模型m3,产生错误e3 …最终预测结果是:m1+m2+m3+…GB…

Oracle21c数据库普通用户创建及授权,建表,创建存储过程、序列、触发器

一、Oracle数据库错误 ORA-65096 表示你尝试在多租户容器数据库&#xff08;CDB&#xff09;环境中创建一个公共用户&#xff08;common user&#xff09;或角色&#xff0c;但没有使用正确的前缀。在多租户架构中&#xff0c;公共用户的用户名必须以 C## 或 c## 开头。 若想…

【AI智能体】零代码构建AI应用,全网都在喊话歌手谁能应战,一键AI制作歌手信息查询应用

欢迎来到《小5讲堂》 这是《文心智能体平台》系列文章&#xff0c;每篇文章将以博主理解的角度展开讲解。 温馨提示&#xff1a;博主能力有限&#xff0c;理解水平有限&#xff0c;若有不对之处望指正&#xff01; 目录 文心智能体大赛背景创建应用平台地址快速构建【基础配置】…

【Web后端】servlet基本概念

1.ServletAPI架构 HttpServlet继承GenericServletGenericServlet实现了Servlet接口&#xff0c;ServletConfig接口,Serializable接口自定义Servlet继承HttpServlet 2.Servlet生命周期 第一步&#xff1a;容器加载Servlet第二步&#xff1a;调用Servlet的无参构造方法&#xf…

Android 获取已安装应用、包名、应用名、版本号、版本名

1、相关代码 List<ApplicationInfo> installedApps getPackageManager().getInstalledApplications(0);for (ApplicationInfo appInfo : installedApps) {CharSequence getAppName getPackageManager().getApplicationLabel(appInfo);String appNamegetAppName.toStrin…