RTOS学习笔记--FreeRTOS的列表和列表项

RTOS学习笔记–FreeRTOS的列表和列表项

本文基于正点原子RTOS开发指南,笔记自用,获取详细信息请关注正点原子官方账号

列表和列表项的简介

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

列表项就是列表项中的项目,相当于链表中的节点

在这里插入图片描述

注意以下几点

  1. 列表相当于链表,列表项相当于节点,FreeRTOS 中的列表是一个双向环形链表
  2. 列表的特点:列表项间的地址非连续的,是人为的连接到一起的。列表项的数目是由后期添加的个数决定的,随时可以改变
  3. 数组的特点:数组成员地址是连续的,数组在最初确定了成员数量后期无法改变

在OS中任务的数量是不确定的,并且任务状态是会发生改变的,所以非常适用列表(链表)这种数据结构

RTOS中列表项的实现

在list.c 和list.h中

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

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

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

  4. 成员变量 xListEnd 是一个迷你列表项,排在最末尾
    其结构如下,

在这里插入图片描述

列表项

列表项列表中用于存放数据的地方,在list.h文件中,关于列表项相关结构体的定义如下

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为列表项的值,这个值多用于按升序对列表中的列表项进行排序,如下图所示,新增一个列表项 值为5,按照值对齐升序排列,所
    在这里插入图片描述

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

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

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

列表项结构示意图

列表项就是用来存放数据的
在这里插入图片描述

mini列表项

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

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的介绍

函数描述
vListInitialise()初始化列表
vListInitialiseItem()初始化列表项
vListInsertEnd()列表末尾插入列表项
vListInsert()列表插入列表项 按照升序插入
uxListRemove()列表移除列表项
初始化列表
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;

    /* 初始化时,列表中的列表项数量为 0(不包含 xListEnd) */
	listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
    listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
} 

初始化后的列表结构如图所示
在这里插入图片描述

初始化列表项
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 );
} 

结构图

在这里插入图片描述

插入数据,按值升序方式
/*函数介绍:pxList要插入的列表 pxNewListItem:要插入该列表的列表项*/
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 )++;							
}

其结构图及代码实现如下

在这里插入图片描述

插入数据,以末尾的方式插入
/*插入参数:pxListu 要插入的列表 pxNewListItem:要插入的列表项 */
void vListInsertEnd (  List_t * const pxList ,   ListItem_t * const pxNewListItem  )
{
	 省略部分非关键代码 …
     /* 获取列表 pxIndex 指向的列表项 */
     ListItem_t * const pxIndex = pxList->pxIndex;
     
     /* 更新待插入列表项的指针成员变量 */
     pxNewListItem->pxNext = pxIndex;
     pxNewListItem->pxPrevious = pxIndex->pxPrevious;
     
     /* 更新列表中原本列表项的指针成员变量 */
     pxIndex->pxPrevious->pxNext = pxNewListItem;
     pxIndex->pxPrevious = pxNewListItem;
     
	/* 更新待插入列表项的所在列表成员变量 */
	pxNewListItem->pxContainer = pxList;
	
	/* 更新列表中列表项的数量 */
	( pxList->uxNumberOfItems )++;
} 


其结构如下所示

在这里插入图片描述

移除数据
/* pxItemToRemove:要移除的列表项,因为可以通过当前列表项找到其所属的列表*/
/*返回值 剩余的列表项的数量*/
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) 
{
	List_t * const pxList = pxItemToRemove->pxContainer; 

    /*从列表中移除列表项 */
	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext; 	
 	/*如果 pxIndex 正指向待移除的列表项 */
    
	if( pxList->pxIndex == pxItemToRemove ) 
	{
        /*pxIndex 指向上一个列表项*/ 
	 	pxList->pxIndex = pxItemToRemove->pxPrevious;
	} else 
	{ 
		mtCOVERAGE_TEST_MARKER(); 
	} 

    /*将待移除的列表项的所在列表指针清空*/ 
	pxItemToRemove->pxContainer = NULL; 
    
	/*更新列表中列表项的数量*/ 
	( pxList->uxNumberOfItems )--; 
	
    /*返回移除后的列表中列表项的数量*/ 
	return pxList->uxNumberOfItems; 
}

结构图示
在这里插入图片描述

  1. item2的上一个的下一个 指向item2的下一个
  2. item2 的下一个的上一个 指向item2 的上一个
  3. 当前列表项指针指向上一个列表项
  4. 清空列表项所指向的列表
  5. 将列表的数量减1
  6. 返回列表项数目
代码演示
/**************************结束***************************/

/*****************第五步:列表项3插入列表******************/
项目				地址
TestList->xListEnd->pxNext	0x200000b8
TestListItem1->pxNext		0x200000cc
TestListItem2->pxNext		0x200000e0
TestListItem3->pxNext		0x200000ac
TestList->xListEnd->pxPrevious	0x200000e0
TestListItem1->pxPrevious		0x200000ac
TestListItem2->pxPrevious		0x200000b8
TestListItem3->pxPrevious		0x200000cc
/**************************结束***************************/

/*******************第六步:移除列表项2********************/
项目				地址
TestList->xListEnd->pxNext	0x200000b8
TestListItem1->pxNext		0x200000e0
TestListItem3->pxNext		0x200000ac
TestList->xListEnd->pxPrevious	0x200000e0
TestListItem1->pxPrevious		0x200000ac
TestListItem3->pxPrevious		0x200000b8
/**************************结束***************************/

/****************第七步:列表末尾添加列表项2****************/
项目				地址
TestList->pxIndex		0x200000b8
TestList->xListEnd->pxNext	0x200000cc
TestListItem1->pxNext		0x200000e0
TestListItem2->pxNext		0x200000b8
TestListItem3->pxNext		0x200000ac
TestList->xListEnd->pxPrevious	0x200000e0
TestListItem1->pxPrevious		0x200000cc
TestListItem2->pxPrevious		0x200000ac
TestListItem3->pxPrevious		0x200000b8
/************************实验结束***************************/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值