在 FreeRTOS 中,vListInsertEnd
函数用于将新项插入到指定列表的尾部(但实际行为是插入到一个特定的索引位置之前)。FreeRTOS 使用双向链表(doubly linked list)来管理任务和其他系统对象,这样可以高效地插入、删除和遍历列表。
1. vListInsertEnd
函数源码解析
vListInsertEnd
函数将新项插入到列表中 pxIndex
指向的列表项之前。以下是该函数的实现:
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 )++;
}
2. 代码详解
-
获取列表
pxIndex
指向的列表项:ListItem_t * const pxIndex = pxList->pxIndex;
pxIndex
是一个指向列表中某一项的指针。该项将作为新项插入位置的参考点。 -
更新待插入列表项的指针成员变量:
pxNewListItem->pxNext = pxIndex; pxNewListItem->pxPrevious = pxIndex->pxPrevious;
新列表项 pxNewListItem
的 pxNext
指向 pxIndex
,即插入项的下一个项。
pxNewListItem
的 pxPrevious
指向 pxIndex
的前一个项。
-
更新列表中原本列表项的指针成员变量:
pxIndex->pxPrevious->pxNext = pxNewListItem; pxIndex->pxPrevious = pxNewListItem;
pxIndex
前一个项的 pxNext
更新为指向 pxNewListItem
,这样链表中的前一项就指向了新插入的项。
pxIndex
的 pxPrevious
更新为 pxNewListItem
,因此 pxIndex
的前一项变为新插入的项。
-
更新待插入列表项的所在列表成员变量:
pxNewListItem->pxContainer = pxList;
pxNewListItem
的 pxContainer
设置为 pxList
,表示该项属于这个列表
-
更新列表中列表项的数量:
( pxList->uxNumberOfItems )++;
列表的项数增加一。
3. 实例分析
以下是 vListInsertEnd
函数的几个示例,以帮助理解其工作原理。
例子 1: 空列表
初始状态:
- 列表
pxList
为空,pxIndex
指向列表头。
List_t list;
ListItem_t listItem1;// 初始化列表
list.pxIndex = &listItem1;
list.uxNumberOfItems = 0;// 插入新项
vListInsertEnd(&list, &listItem1);
插入后:
pxList
现在包含一项listItem1
。listItem1
的pxNext
和pxPrevious
都指向listItem1
自己。
例子 2: 已有多个项的列表
初始状态:
- 列表
pxList
包含listItem1
、listItem2
,pxIndex
指向listItem2
。
List_t list;
ListItem_t listItem1, listItem2, listItem3;// 初始化列表
list.pxIndex = &listItem2;
list.uxNumberOfItems = 2;listItem1.pxNext = &listItem2;
listItem1.pxPrevious = &listItem2;listItem2.pxNext = &listItem1;
listItem2.pxPrevious = &listItem1;// 插入新项
vListInsertEnd(&list, &listItem3);
插入后:
listItem3
被插入到listItem2
前。- 列表顺序为:
listItem1 -> listItem3 -> listItem2
。
例子 3: 插入到非尾部
初始状态:
- 列表
pxList
包含listItem1
,listItem2
,listItem3
,pxIndex
指向listItem2
。
List_t list;
ListItem_t listItem1, listItem2, listItem3, listItem4;// 初始化列表
list.pxIndex = &listItem2;
list.uxNumberOfItems = 3;listItem1.pxNext = &listItem2;
listItem1.pxPrevious = &listItem3;listItem2.pxNext = &listItem3;
listItem2.pxPrevious = &listItem1;listItem3.pxNext = &listItem1;
listItem3.pxPrevious = &listItem2;// 插入新项
vListInsertEnd(&list, &listItem4);
插入后:
listItem4
被插入到listItem2
前。- 列表顺序为:
listItem1 -> listItem4 -> listItem2 -> listItem3
。
4. 适用场景
- 任务调度:在 FreeRTOS 中,任务可以被插入到就绪任务列表中以表示它们可以运行。
- 时间管理:延迟任务可以插入到延迟列表中,以便当时间到达时,任务会被恢复。
- 资源管理:可以用于管理队列、信号量等对象的列表。
vListInsertEnd
是 FreeRTOS 中用于在列表中插入新项的函数。虽然名称暗示插入到末尾,但实际功能是插入到 pxIndex
指向项的前面。函数通过更新指针来维持双向链表的完整性,同时增加列表项的数量。这种结构使得 FreeRTOS 可以高效管理任务和系统资源,从而确保实时操作系统的高效运行。