FreeRTOS

FreeRTOS,第1张

FreeRTOS(一) 链表浅析
      • C语言链表简介
      • 列表及列表项
      • 链表相关 *** 作

C语言链表简介

链表好比一个圆形的晾衣架,上面有很多的钩子,钩子首尾相连。


链表由许多节点组成,节点与节点之 间首尾相连。


晾衣架的钩子本身不能代表很多东西,但是钩子本身可以挂很多东西。


同样链表也类似,链表的节点本身不能存储太多东西,但是节点跟晾衣架的钩子一样,可以挂很多数据。


列表及列表项
  • 列表项
/* 列表节点数据结构定义[list.h] */
typedef struct xLIST_ITEM {
	TickType_t xItemValue;          /* 节点排序,一般用于记录任务从挂起状态返回就绪态的绝对时间 */                
	struct xLIST_ITEM *pxNext;      
	struct xLIST_ITEM *pxPrevious;
	void *pvOwner;                 /* 指向拥有此节点的对象,通常是TCB */
	struct xLIST *pxContainer;     /* 指向此节点所在的列表(链表) */
} 

  • 列表
/* 列表数据结构定义[list.h] */
typedef struct xLIST {
	UBaseType_t uxNumberOfItems; /* 链表中包含的节点数目,不包含根节点 */
	ListItem_t *pxIndex;         /* 用于链表中对节点的索引 */
	MiniListItem xListEnd;       /* 根节点,属于列表最初的钩子 */
} List_t;

typedef struct xMINI_LIST_ITEM {
	TickType_t xItemValue;      /* 默认值为FreeRtos中的最大值,代表此节点是所有节点中的最后一个 */
	ListItem_t *pxNext;   
	ListItem_t *pxPrevious;
} MiniListItem_t;

列表中默认包含的节点 xListEnd 仅用于抓取最开始加入的节点,也被称为根节点。



一般认为 xListEnd->pxNext 指向列表加入的第一个节点,而 xListEnd->pxPrevious 指向
列表加入的最后一个节点。


链表相关 *** 作
  • 列表项初始化
void vListInitializeItem(ListItem_t * const pxItem)
{
	/* 初始化该节点所在链表为空,表示节点还没有插入任何链表 */
	pxItem->pvContainer = NULL;
}
  • 列表初始化
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);
	
	/* 链表节点计数器初始为0,计数不包括根节点 */
	pxList->uxNumberOfItems = (UBaseType_t)0U;
}

  • 将节点插入链表尾部
/* 根据代码可知,其实是将新节点插入到列表索引指针pxIndex指向节点的前面,
而不是根节点前面,而pxIndex只是初始化时指向了根节点 */
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->pxContainer = pxList;
    (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)
        {
            /* do nothing */
        }
    }

	pxNewListItem->pxNext = pxIterator->pxNext;
	pxNewListItem->pxPrevious = pxIterator;
	pxIterator->pxNext->pxPrevious = pxNewListItem;
	pxIterator->pxNext = pxNewListItem;

	/* 记住节点所在列表 */
	pxNewListItem->pxContainer = pxList;
	/* 列表计数器++ */
	(pxList->uxNumberOfItems)++;
}
  • 将节点从列表删除
/* 个人疑问:pxItemToRemove在被删除后,它的pxNext和pxPrevious仍然指向原来的前后节点,
那如果在相邻节点(0,1,2)中,删除1节点,再删除2节点后,此时如果不小心再次删除1节点,
岂不是0,2节点会再次相连? */
UBaseType_t uxListRemove(ListItem_t * const pxItemToRemove)
{
	/* 获取节点所在列表 */
	List_t * const pxList = pxItemToRemove->pxContainer;

	pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
	pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;

	/* 避免列表索引指针pxIndex指向已被删除的节点 */
	if( pxList->pxIndex == pxItemToRemove )
    {
        pxList->pxIndex = pxItemToRemove->pxPrevious;
    }

	pxItemToRemove->pxContainer = 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 )                       \
		( ( ( pxList )->uxNumberOfItems == ( UBaseType_t ) 0 ) ? pdTRUE : pdFALSE )

/* 获取列表的节点数 */
#define listCURRENT_LIST_LENGTH( pxList )                 \
		( ( pxList )->uxNumberOfItems )

/* 返回当前节点的下一个节点的owner,同一优先级的任务的按照时间片的方式切换就与此函数有关 */
#define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                           
    {                                                                                          
        List_t * const pxConstList = ( pxList );                                                                     
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                           
        /* 依次返回列表中所有的节点owner,但需要跳过根节点 */
        if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) ) 
        {                                                                                      
            ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                       
        }                                                                                      
        ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                         
    }

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/578162.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-11
下一篇 2022-04-11

发表评论

登录后才能评论

评论列表(0条)

保存