目录
列表和列表项的简介
列表和列表项的关系
列表相关API函数介绍
函数vListInitialiseI()
函数vListInitialiseItem()
函数vListInsert()
函数vListInsertEnd()
函数uxListRemove()
列表和列表项的简介
列表是FreeRTOS中的一个数据结构,概念上和链表有点类似,列表被用来跟踪FreeRTOS的任务,列表项就是存放在列表中的项目。
列表相当于链表,列表项相当于节点,FreeRTOS中的列表是一个双向环形链表。
列表的特点:列表项间的地址是非连续的,是人为连接到一起的,列表项的数目是由后期添加的个数决定的,随时可以改变。
数组的特点:数组成员地址是连续的,数组在最初确定了成员数量后期无法改变。
在OS中任务的数量是不确定的,并且任务状态是会发生改变的,所以非常适合用列表(链表)这种数据结构。
有关于列表的东西均在文件list.c和list.h中,首先看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、在该结构体中,包含了两个宏,这两个宏是确定的已知常量,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;
列表项结构示意图
1、成员变量xItemValue为列表项的值,这个值多用于按升序对列表中的列表项进行排序。
2、成员变量pxNext和pxPrevious分别用于指向列表中列表项的下一个列表项和上一个列表项。
3、成员变量pxOwner用于指向包含列表项的对象(通常是任务控制块)
4、成员变量pxContainer用于指向列表项所在列表
迷你列表项
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() | 列表移除列表项 |
函数vListInitialiseI()
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 );
}
上述函数中的形参为pxList,即待初始化列表
函数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 );
}
函数vListInsert()
每个列表项对象从结构体中都可以看出来有一个列表项值(xItemValue),通常是一个被追踪的任务优先级或是一个调度事件的计数器值。调用API函数vListInsert可以将pxNewListItem指向的列表项插入到pxList指向的列表中,列表项在列表的位置由pxNewListItem->xItemValue决定,按照升序排列。
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 )
{
/* There is nothing to do here, just iterating to the wanted
* insertion position. */
}
}
/*更新待插入列表项所在列表的关联关系和数量等变量*/
pxNewListItem->pxNext = pxIterator->pxNext;
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxIterator->pxNext = pxNewListItem;
/* Remember which list the item is in. This allows fast removal of the
* item later. */
pxNewListItem->pxContainer = pxList;
( pxList->uxNumberOfItems )++;
}
函数vListInsert(0,是将待插入列表的列表项按照列表项的升序进行排列,有序的插入到列表中,这是一种有序插入。
函数vListInsertEnd()
void vListInsertEnd( List_t * const pxList,
ListItem_t * const pxNewListItem )
{
/*获取列表pxIndex指向的列表项*/
ListItem_t * const pxIndex = pxList->pxIndex;
/* Only effective when configASSERT() is also defined, these tests may catch
* the list data structures being overwritten in memory. They will not catch
* data errors caused by incorrect configuration or use of FreeRTOS. */
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* 更新待插入列表项的指针成员变量*/
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
/* Only used during decision coverage testing. */
mtCOVERAGE_TEST_DELAY();
/*更新列表中原本列表项的指针成员变量*/
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
/* 更新待插入列表项的所在列表成员变量*/
pxNewListItem->pxContainer = pxList;
/*更新列表中列表项的数量*/
( pxList->uxNumberOfItems )++;
}
函数vListInsertEnd(),是将待插入的列表项插入到列表pxIndex指针指向的列表项前面;它是一种无序的插入方法。
函数uxListRemove()
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;
}
参考相关博客
FreeRTOS高级篇1---FreeRTOS列表和列表项_研究是为了理解的博客-CSDN博客_freertos列表