题记:知其然且知其所以然
理解 FreeRTOS 中的代码,不仅要了解它们的结构和用途,还要理解这些设计选择背后的原因。我个人就自己的学习中的问题表达一下自己的想法,请各位大神批评指正。
1、链表、节点介绍
链表就像一个圆形的衣架,衣架上面有很多钩子。每一个钩子代表一个节点。这些钩子本身不带有其他东西,但是每个钩子都可以挂载数据。FreeRTOS 中的列表(list)是一个双向链表:每个节点包含两个指针:一个指向前一个节点,一个指向下一个节点。这种结构提供了双向的遍历能力,使得可以在链表中进行双向的操作。
在这里笔者不对数据结构链表做过多的详细介绍,主要是针对FreeRTOS的代码,我们的目的就是读懂代码。本次学习过程基于野火FreeRTOS的教程。
2、LIST和LIST_ITEM
对应关系:
LIST(列表) | FreeRTOS中是双向链表,用于管理多个列表项。 |
---|---|
LIST_ITEM(列表项) | 代表链表中的一个节点,包含任务的相关信息(如优先级、延时时间等) |
后面这左边和右边等价使用。
3、代码分析之关于链表结构体
(1)xLIST链表结构体(list.h文件定义)
这里出现了三个数据类型和结构。
UBaseType_t | typedef unsigned long UBaseType_t;这是一个无符号长整型类型(32位) |
---|---|
ListItem_t * pxIndex; | pxIndex 是一个指向 ListItem_t 类型的指针,表示节点索引。 |
MiniListItem_t xListEnd | MiniListItem_t:用于表示链表的头节点,在这写的是end,无须担心,因为双向链表尾就是头。 |
接下来我们将逐步分析出现的新结构体
(2)ListItem_t节点结构体(list.h)
TickType_t xItemValue | typedef uint32_t TickType_t;无符号32位整型,辅助节点排列,后面确定优先级会用到。 |
---|---|
struct xLIST_ITEM *pxNext struct xLIST_ITEM *pxPrevious | 结构体定义中包含指向自身类型的指针。分别指向上一个和下一个链表。 |
void * pvOwner; void * pvContainer; | 无类型指针(void *),列表项所在的内核对象TCB(任务控制块(Task Control Block,TCB)和列表项所在的列表。 |
关于无类型指针void 和指针函数和函数指针,我将新写一个文件再说。
TCB:用于存储与每个任务相关的所有信息,这个结构体后面再任务章节会介绍
学到这的时候笔者想到一个问题
①问题:指向指向拥有该节点的内核对象,通常是TCB。按照前面的说法一个任务应该代表一个列表项,整个系统所有任务可以视为一个链表,我可以在结构体定义的时候直接指明是什么任务不就行了吗,为什么要在列表项里面专门定义?
其实这就是意味着一个任务可以有多个列表项在不同的列表,虽然从整体上看,所有任务可以被视为一个链表,但在FreeRTOS中,任务的状态管理需要更加细致的控制。
多个链表项作用举例:
多种任务状态:任务可以处于不同的状态,如就绪、延时、阻塞等。每个状态对应一个不同的列表。例如,就绪任务在就绪列表中,延时任务在延时列表中,等待资源的任务在等待列表中。假设我们有一个任务,它可能同时处于延时列表和信号量等待列表中,也就对应一个任务多个节点。这两个列表还没学到,暂不做介绍。
(3)MiniListItem_t:头节点结构体(list.h)
①问题:为啥头节点不用pvOwner和pvContainer?
在后面的初始化代码中,我看到了初始化和插入节点的操作。意识到,这个头结点算是一个地标,标明这里是链表的头,用于定位使用,不被任何任务拥有,因此这么定义。
个人学习文档,有问题欢迎大家评论交流,如果感到有用的话点个赞吧( •ᴗ• )。