注:在使用大多数功能时,FreeRTOS都要将对应的宏置为1,具体的需要查看FreeRTOS官方文档。
列表相关API函数
函数基础
初始化列表和列表项
初始化列表
1.vListInitialise():
1 | void vListInitialise(List_t * const pxList);
参数:
- pxList:待初始化的列表。
此函数用于初始化列表,在定义列表之后,需要先对其进行初始化, 只有初始化后的列表,才能够正常地被使用。
初始化列表项
2.vListInitialiseItem():
void vListInitialiseItem(ListItem_t * const pxItem);
参数:
- pxItem:待初始化的列表项
此函数用于初始化列表项,如同列表一样,在定义列表项之后,也需要先对其进行初始化。
插入列表项
升序插入
vListInsert():
void vListInsert( List_t * const pxList,
ListItem_t * const pxNewListItem );
参数:
- pxList:待初始化的列表
- pxNewListItem:待插入的列表项
此函数用于将待插入列表的列表项按照列表项值升序排序的顺序,有序地插入到列表中
末尾插入
vListInsertEnd():
void vListInsertEnd( List_t * const pxList,
ListItem_t * const pxNewListItem );
参数:
- pxList:选择插入的列表
- pxNewListItem:待插入列表项
此函数用于将待插入列表的列表项插入到列表 pxIndex 指针指向列表项的前面,是一种无序的插入方法。
移除列表项
uxListRemove():
UBaseType_t uxListRemove(ListItem_t * const pxItemToRemove);
参数:
- pxItemToRemove:待移除的列表项
该函数存在一个返回值为整数类型,表示的是待移除列表项在移除后,所在列表剩余的列表项数量。
函数的内部实现
由于这几个函数内部实现代码较少,我们直接从源码进行分析。
初始化列表
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 );
}
在源码中做出注释如上,总结来说,初始化列表函数内部做的事情就是把列表的参数初始化为末尾列表项,比如将pxIndex指针指向末尾列表项,将排序值xItemValue设置为portMAX_DELAY(0xFFFFFFFF)等等。
初始化列表项
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 );
}
初始化列表项函数更加简单,由于末尾列表项并不应该属于任何列表,所以将其设置为NULL。
插入列表项(升序插入)
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 )++;
}
通过上述源码,我们可以知道,vListInsert函数通过每个列表项中设置的xItemValue值,通过遍历其他列表的该数值,找到比插入列表的数值小的第一个列表,并将其插入中间。后续的步骤则是通过遍历到的位置,进行与前面和后面列表的连接。
总结来说,这个函数的插入列表项是根据列表项的数值进行插入,所以是一种有序的插入操作。
插入列表项(末尾插入)
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 )++;
}
从上述源码分析,该函数根据pxIndex所指向的列表项1,将所需要插入的列表项2插入到列表项1的前面,后续操作则是和之前的函数重复,进行列表之间的手拉手操作。该pxIndex所指向的列表项并不是固定的,而是列表中的pxIndex指针当时所指向的列表项,所以是一直在变化的。并且,我们会发现,该函数并不需要获取列表项的数值,因为完全依赖于pxIndex所指的列表项进行插入操作。
总结来说,vListInsertEnd函数虽然叫做末尾插入列表项函数,但是从源码中我们可以知道,这个函数最终所作的其实是一种无序插入的操作。
移除列表项
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;
}
从代码分析,移除列表项的过程,其实就是根据待移除列表项前面和后面列表项的连接断开,并且让他们之间连接即可。
以上就是所有关于列表相关的函数,函数内容其实不难,建议大家还是自己阅读源码分析一下。