从零开始掌握FreeRTOS(2)链表之节点的定义

目录

节点

节点定义

节点实现

根节点

根节点定义

 精简节点定义

根节点实现


      在上篇文章,我们完成了 FreeRTOS 的移植。在 FreeRTOS 中,所有功能被划分为任务。而任务则需要挂载链表上面。在本章,我们将掌握链表的各种节点类型。

        在创建任务之前,我们需要先了解FreeRTOS的运转机制。FreeRTOS是一个多任务系统,由操作系统来管理执行每个任务。这些任务全都挂载到一个双向循环链表上。同时链表的每个节点都能挂载多个任务。

节点

节点定义

        在 FreeRTOS 中,关于链表的定义在 list.h 中实现。下面代码为链表节点的结构体定义。

PS:在 list.h 中,我的宏 configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES 设置为0,当其为0时,listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE 和 listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE 这两个宏不代表实际值,为提高可读性所以我在后续出现这两个宏的地方都将他们删去了。

struct xLIST_ITEM
{			
	configLIST_VOLATILE TickType_t xItemValue;			
	struct xLIST_ITEM * configLIST_VOLATILE pxNext;		
	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;	
	void * pvOwner;										
	void * configLIST_VOLATILE pvContainer;							
};
typedef struct xLIST_ITEM ListItem_t;	

configLIST_VOLATILE TickType_t xItemValue:这里的 configLIST_VOLATILE 就是C语言中的VOLATILE类型,在 FreeRTOS 中,所有的数据类型都被 typedef 进行了重新定义。同理,TickType_tuint32_t,所有的数据类型都在 portmacro.h 中进行了定义。再说回 xItemValue ,这个参数的作用就是做节点的序号。

struct xLIST_ITEM * configLIST_VOLATILE pxNext:指向下一个节点。  

struct xLIST_ITEM * configLIST_VOLATILE pxPrevious:指向上一个节点。     

void * pvOwner:指向该节点的数据结构。指向包含列表项的对象(通常是 TCB)的指针。 因此,包含列表项的对象与列表项本身之间存在双向链接。

        在FreeRTOS中,TCB(Task Control Block)是任务控制块的缩写。它是一个数据结构,用于存储和管理任务的所有相关信息。每个任务都有一个对应的TCB,FreeRTOS通过TCB来管理和调度任务。之后会在其他文章中进行解释。                                       

void * configLIST_VOLATILE pvContainer:指向该节点所在的链表,通常指向链表的根节点。    

typedef struct xLIST_ITEM ListItem_t:将该结构体的数据类型重新定义。

节点实现

在 list.c 中,通过定义函数来实现节点的创建。下面为节点初始化函数。

void vListInitialiseItem( ListItem_t * const pxItem )
{
	pxItem->pvContainer = NULL;
}

        由于该节点仅完成了初始化,未插入到链表中,所以初始化链表为空。实际情况如下图。

        3dffccbbd4064918a2b98e6531549af1.png

根节点

根节点定义

        上文提到,pvContainer 通常指向链表的根节点。下面为根节点的结构体定义。

typedef struct xLIST
{
	volatile UBaseType_t uxNumberOfItems;
	ListItem_t * configLIST_VOLATILE pxIndex;
	MiniListItem_t xListEnd;
} List_t;

uxNumberOfItems:节点计数器。表示除根节点外,链表的节点数量。

pxIndex:链表节点索引指针,用于遍历节点。

xListEnd: 链表最后一个节点。由于 FreeRTOS 是双向循环链表,所以最后一个节点也就是第一个节点。

 精简节点定义

        精简节点,就是根节点中 xListEnd 的数据类型,个人认为是对根节点的节点类型补充。

struct xMINI_LIST_ITEM
{
	configLIST_VOLATILE TickType_t xItemValue;
	struct xLIST_ITEM * configLIST_VOLATILE pxNext;
	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
};
typedef struct xMINI_LIST_ITEM MiniListItem_t; 

        从定义上看,精简节点就是由指向上一个和下一个节点的指针和序号组成,结构体成员都是构成节点的最基本要素。 

根节点实现

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;
}

这个根节点初始化函数做了四件事:

1. 将索引指针指向最后一个节点。

2. 将序号值设为最大(即portMAX_DELAY,其在 portmacro.h 中进行了定义),以确保根节点是链表最后一个节点。

3. 将该节点的前一个和后一个节点都指向自己。

4. 将计数器的值初始为0。

        如下图所示,其为一个根节点。根节点除了包含承担节点作用的精简节点外,还有索引指针和节点计数器组成。但在初始化中,pxNext 和 pxPrevious 都指向自身。

7110a412ccb44ddeb1ca2d016af0db1b.png

        在了解上述节点的定义和初始化之后,将根节点和节点组合在一起形成的链表如下图所示。在下一篇文章中,我们来分析如何将节点添加到链表中。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

pQAQqa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值