FreeRTOS链表实现
- 0 概述
- 1 关键结构体
- 1.1 链表基础知识
- 1.2 链表数据结构
- 1.3 链表操作
0 概述
部分内容参考野火的FreeRTOS相关开发资料,在此做一个学习记录总结。
1 关键结构体
FreeRTOS源码实现中存在很多链表相关操作,理解链表相关操作对掌握FreeRTOS实现原理至关重要。
1.1 链表基础知识
FreeRTOS使用双向链表,与数组通过开辟一段连续内存存储数据不同,链表通过把离散的数据(标准C类型或者是用户自定义结构体)链接成一个表,通过对节点的插入和删除操作来实现对数据的存取。
双向链表是一个圈,没有头尾之分,但是为了方便节点的插入和删除操作,需要人为规定一个根节点(root节点)。
如上图所示,如果链表为空,这只有一个root节点,node_num为0,next和previous均指向自身。
为了有助于理解后面相关初始化以及插入删除操作,此处需要记住下面两点:
1)root_node->next指向链表的第一项node1(或自身,如果是空链表)
2)root_node->previous指向链表的最后一项noden(或自身,如果是空链表)
1.2 链表数据结构
struct xLIST_ITEM
{
TickType_t xItemValue;
struct xLIST_ITEM *pxNext;
struct xLIST_ITEM *pxPrevious;
void *pvOwner;
void *pvContainer;
};
typedef struct xLIST_ITEM ListItem_t;
struct xMIN_LIST_ITEM
{
TickType_t xItemValue;
struct xLIST_ITEM *pxNext;
struct xLIST_ITEM *pxPrevious;
};
typedef struct xLIST
{
UBaseType_t uxNumberOfItems;
ListItem_t *pxIndex;
MiniListItem_t xListEnd;
} List_t;
1.3 链表操作
- 根节点初始化
void vListInitialise(List_t * const pxList)
{
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));
pxList->uxNumberOfItems = (UBaseType_t)0U;
}
上面关键的一点是pxList->pxIndex指向根节点,这样后续插入删除操作便可以有了一个其实参考点。
- 节点初始化
这里的节点指的是除根节点外的有效挂载数据的节点,初始化就是告诉程序,该节点未挂到任何链表上,实现代码如下:
void vListInitialiseItem(ListItem_t * const pxItem)
{
pxItem->pvContainer = NULL;
}
- 插入节点至尾部
从前分析可知,链表的根节点,即xListEnd->pxPrevious指向的就是原链表的尾部节点,节点插入尾部时,就是要让新的节点跟在原来尾部节点之后,可以理解为在原尾部节点与根节点之间插入一个节点,代码实现如下:
void vListInsertEnd(List_t * const pxList, ListItem_t * const pxNewListItem)
{
ListItem_t * const pxIndex = pxList->pxIndex;
pxNewListItem->pxNext = pxIndex;
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
pxIndex->pxPrevious->pxNext = pxNewListItem;
pxIndex->pxPrevious = pxNewListItem;
pxNewListItem->pvContainer = (void *)pxList;
(pxList->uxNumberOfItems)++;
}
- 升序插入节点
根据节点的xItemValue辅助值对接点进行排序,如果xItemValue相同,就根据插入顺序排列了。
插入后一定要记得更新链表中节点数据计数器pxList->uxNumberOfItems和新插入节点的pxNewListItem->pvContainer(否则节点就是未挂载在任何链表上)。
void vListInsert(List_t * const pxList, ListItem_t * const pxNewListItem)
{
ListItem_t *pxIterator = NULL;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
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->pvContainer = (void *)pxList;
(pxList->uxNumberOfItems)++;
}
- 删除节点
删除节点后需要清除删除节点的pvContain指向,做好已删除节点原pxNext和pxPrevious指向节点的衔接工作,并且链表节点数目要相应自减。
其中特别注意的是,当删除最后一个节点时,需要调整节点索引指针,即让根节点指向自己,即链表初始化后为空的状态。
UBaseType_t uxListRemove(ListItem_t * const pxItemToRemove)
{
List_t * const pxList = pxItemToRemove->pvContainer;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
pxItemToRemove->pvContainer = NULL;
(pxList->uxNumberOfItems)--;
return pxList->uxNumberOfItems;
}
#define listSET_LIST_ITEM_OWNER(pxListItem, pxOwner) ((pxListItem)->pvOwner = (void *)pxOwner)
#define listGET_LIST_ITEM_OWNER(pxListItem) ((pxListItem)->pvOwner)
#define listSET_LIST_ITEM_VALUE(pxListItem, xValue) ((pxListItem)->xItemValue = xValue)
#define listGET_LIST_ITEM_VALUE(pxListItem) ((pxListItem)->xItemValue)
#define listGET_ITEM_VALUE_OF_HEAD_ENTRY(pxList) (((pxList)->xListEnd).pxNext->xItemValue)
#define listGET_HEAD_ENTRY(pxList) (((pxList)->xListEnd).pxNext)
#define listGET_NEXT(pxListItem) ((pxListItem)->pxNext)
#define listGET_END_MARKER(pxList) ((ListItem_t const *)(&((pxList)->xListEnd)))
#define listLIST_IS_EMPTY(pxList) ((BaseType_t)(((pxList)->uxNumberOfItems) == (UBaseType_t)0))
#define listCURRENT_LIST_LENGTH(pxList) ((pxList)->uxNumberOfItems)
#define listGET_OWNER_OF_NEXT_ENTRY(pxTCB, pxList) \
{ \
List_t * const pxConstList = (pxList); \
\
\
(pxConstList)->pxIndex = (pxConstList)->pxIndex->pxNext; \
if((void *)(pxConstList)->pxIndex == (void *)&((pxConstList)->xListEnd)) \
{ \
(pxConstList)->pxIndex = (pxConstList)->pxIndex->pxNext; \
} \
\
(pxTCB) = (pxConstList)->pxIndex->pvOwner; \
}
#define listGET_OWNER_OF_HEAD_ENTRY(pxList) ((&((pxList)->xListEnd))->pxNext->pvOwner)
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)