本文章参考野火的“[野火®]《FreeRTOS 内核实现与应用开发实战—基于STM32》”,特此申明。
在学习链表之前,先介绍一下freertos的数据类型,在freertos原码中对标准C的数据类型进行了重定义上一张已经介绍过freeRTOS的类型重定义
在FreeRTOS中链表的结构体有三种:
第一种:普通节点的结构体,结构体成员包含:
辅助值:用来帮助节点做顺序排序的,最大值为0xffff或0xffff ffff,由configUSE_16_BIT_TICKS宏决定。
指向上一个节点和下一个节点的两个指针,类似于普通的双向循链表的操作。
pvOwner:指向拥有该节点的内核对象(暂时不知道有何用处)。
pvContainer:指向该节点所在的链表(链表的根节点)。
/*定义普通节点结构体*/
typedef struct xLIST_ITEM
{
TickType_t xItemValue; /*辅助值,用于帮助节点做顺序排列*/
struct xLIST_ITEM *pxNext; /*指向链表下一个节点*/
struct xLIST_ITEM *pxPrevious; /*指向链表上一个节点*/
void *pvOwner; /*指向拥有该节点的内核对象,通常是 TCB */
void *pvContainer; /*指向该节点所在的链表 */
}ListItem_t;
第二种:定义最后一个链表节点的结构体
/*定义最后一个链表节点的结构体*/
typedef struct xMINI_LIST_ITEM
{
TickType_t xItemValue; /*辅助值,用于帮助节点做升序排列 */
struct xLIST_ITEM * pxNext; /*指向链表下一个节点 */
struct xLIST_ITEM * pxPrevious; /*指向链表前一个节点 */
}MiniListItem_t;
第三种:定义根节点结构体
/*定义根节点结构体*/
typedef struct xLIST
{
UBaseType_t uxNumberOfItems; /*链表节点计数器,节点总数*/
ListItem_t *pxIndex; /*链表节点索引指针*/
MiniListItem_t xListEnd; /*链表最后一个节点*/
}List_t;
对链表的初始化
/*链表根节点初始化*/
void vListInitialise( List_t * const pxList )
{
/*将链表索引指针指向最后一个节点*/
pxList->pxIndex = (ListItem_t *)&pxList->xListEnd;
/*设置链表最后一个节点的辅助排序值为最大*/
pxList->xListEnd.xItemValue = portMAX_DELAY;
/*设置链表最后一个节点的前一个和后一个节点指向本身,说明该链表为空*/
pxList->xListEnd.pxPrevious = (ListItem_t *)&pxList->xListEnd;
pxList->xListEnd.pxNext = (ListItem_t *)&pxList->xListEnd;
/*设置链表节点数为0*/
pxList->uxNumberOfItems = (UBaseType_t) 0U;
}
/*普通节点初始化*/
void vListInitialiseItem( ListItem_t * const pxItem )
{
/*初始化链表所在节点为空,表示未插入任何链表*/
pxItem->pvContainer = NULL;
}
对链表的增删改查
/*把节点插入到链表的尾部*/
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;
/*该链表的节点数加1*/
( pxList->uxNumberOfItems )++;
}
/*把该节点按升序插入*/
void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
/*定义一个不可改变的变量存放该节点的辅助值*/
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 )++;
}
/*删除节点*/
UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
{
/*找到该节点所在的链表*/
List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;
pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
/*如果删除的时索引则将索引变成上一个*/
if( pxList->pxIndex == pxItemToRemove )
{
pxList->pxIndex = pxItemToRemove->pxPrevious;
}
pxItemToRemove->pvContainer = NULL;
( pxList->uxNumberOfItems )--;
return pxList->uxNumberOfItems;
}
验证
#include "list.h"
struct xLIST List_Test1;
struct xLIST List_Test2;
struct xLIST_ITEM List_Item1;
struct xLIST_ITEM List_Item2;
struct xLIST_ITEM List_Item3;
struct xLIST_ITEM List_Item4;
int main()
{
vListInitialise( &List_Test1 );
vListInitialise( &List_Test2 );
vListInitialiseItem( &List_Item1 );
List_Item1.xItemValue = 1;
vListInitialiseItem( &List_Item2 );
List_Item2.xItemValue = 2;
vListInitialiseItem( &List_Item3 );
List_Item3.xItemValue = 3;
vListInitialiseItem( &List_Item4 );
List_Item4.xItemValue = 4;
vListInsert( &List_Test1, &List_Item2 );
vListInsert( &List_Test1, &List_Item1 );
vListInsert( &List_Test1, &List_Item3 );
vListInsert( &List_Test2, &List_Item4 );
for(;;)
{
}
}