参考学习正点原子FreeRtos第七章
先对列表,列表项,迷你列表项介绍(这部分看书就行),其次是对列表项初始化等进行分析,配合实验进行理解
列表
列表是FreeRTOS中的一个数据结构,概念上和链表有点类似,列表被用来跟踪FreeRTOS中的任务。与列表相关的全部东西都在文件 list.c和 list.h中。在list.h 中定义了一个叫List_t 的结构体,如下:
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE (1)
configLIST_VOLATILE UBaseType _t uxNumberOfItems; (2)
ListItem_t *configLIST_VOLATILE pxIndex; (3)
MiniListItem_t xListEnd; (4)
listSECOND_LIST_INTEGRITY_CHECK_VALUE (5)
}List t;
重点关注示意图中几个成员,列表项和迷你列表项也是如此
列表项
列表项就是存放在列表中的项目,FreeRTOS提供了两种列表项:列表项和迷你列表项。这两个都在文件 list.h 中有定义,先来看一下列表项,定义如下:
struct xLIST_ITEM1
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE (1)
configLIST_VOLATILE Tick Type_t xltemValue; (2)
struct xLIST_ITEM * configLIST_VOLATILEpxNext; (3)
struct xLIST_ITEM *configLIST_VOLATILE pxPrevious; (4)
void *pvOwner; (5)
void * configLIST_VOLATILE pvContainer; (6)
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE (7)
};
typedef struct xLIST_ITEM ListItem_t;
迷你列表项
上面我们我们说了列表项,现在来看一下迷你列表项,迷你列表项在文件 list.h中有定义,如下:
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE (1)
configLIST_VOLATILE TickType_t xltem Value; (2)
struct xLIST_ITEM * configLIST_VOLATILE pxNext; (3)
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; (4)
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
列表初始化
新创建或者定义的列表需要对其做初始化处理,列表的初始化其实就是初始化列表结构体List_t中的各个成员变量,列表的初始化通过使函数vListInitialise()来完成,此函数在list.c中有定义,函数如下:
void vListInitialise( List_t * const pxList )
{
pxList->pxIndex = (Listltem_t * )&( pxList->xListEnd ); (1)
pxList->xListEnd.xItemValue = portMAX_DELAY; (2)
pxList->xListEnd.pxNext= (Listltem_t* )&( pxList->xListEnd ); (3)
pxList->xListEnd.pxPrevious = (ListItem_t* ) &(pxList->xListEnd ); (4)
pxList->uxNumberOfltems = ( UBaseType_t ) OU; (5)
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList ); (6)
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ); (7)
}
pxList 就是要初始化的列表,那么来看看之前的示意图
xListEnd 用来表示列表的末尾,上面也有介绍xListEnd 就是一个迷你列表项,看看迷你列表项的示意图
也就是说创建一个列表后,里面就已经包含了一个迷你列表项,列表pxIndex是用来索引列表项的,那么列表初始化函数中(1)意思,当前列表索引pxList->pxIndex指向就只有创建列表时迷你列表项的地址
(2)的意思书中有解释
(3)(4)就是将迷你列表项中的指针都指向xListEnd 地址
(5)就是将列表项的值初始化为0,很明显没有包含列表初始化时xListEnd (迷你列表项)
列表项初始化
同列表一样,列表项在使用的时候也需要初始化,列表项初始化由函数vListInitialiseltem()来完成,函数如下:
void vListInitialiseItem( ListItem_t * const pxItem )
{
pxltem->pvContainer =NULL; //初始化 pvContainer为 NULL
//初始化用于完整性检查的变量,如果开启了这个功能的话。
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
};
列表初始化很简单,只是将列表项成员变量pvContainer初始化为NULL,并且给用于完整性检查的变量赋值。书中也有解释,列表项的成员变量比列表要多,怎么初始化函数就这么短?其他的成员变量什么时候初始化呢?这是因为列表项要根据实际使用情况来初始化,比如任务创建函数xTaskCreate()就会对任务堆栈中的xStateListltem和xEventListItem这两个列表项中的其他成员变量在做初始化,任务创建过程后面会详细讲解。
列表项插入
函数vListInsert()的参数pxList决定了列表项要插入到哪个列表中,pxNewListItem决定了要插入的列表项,但是这个列表项具体插入到什么地方呢?要插入的位置由列表项中成员变量xItemValue来决定。列表项的插入根据xItemValue 的值按照升序的方式排列!接下来我们来具体看一下函数vListInsert()的整个运行过程,函数代码如下:
//pxList: 列表项要插入的列表
//pxNewListItem : 要插入的列表项
void vListInsert( List_t *const pxList, ListItem_t *const pxNewListItem )
{
Listltem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue; (1)
listTEST_LIST_INTEGRITY( pxList ); (2)
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
if( xValueOfInsertion == portMAX_DELAY ) (3)
{
pxIterator = pxList->xListEnd.pxPrevious; (4)
}
else
{
for( pxIterator = ( ListItem_t * )&( pxList->xListEnd ); pxIterator->\(5)
pxNext->xItemValue <=xValueOfInsertion; pxIterator = pxIterator->pxNext )
{
//空循环,什么也不做!
}
}
pxNewListItem->pxNext = pxIterator->pxNext; (6)
pxNewListItem->pxNext->pxPrevious = pxNewListItem;
pxNewListItem->pxPrevious = pxIterator;
pxlterator->pxNext = pxNewListItem;
pxNewListltem->pvContainer = ( void * ) pxList; (7)
(pxList->uxNumberOfltems)++; (8)
}
先看列表项示意图
先看(1)xValueOfInsertion 中保存的是要插入列表项的列表项值
(3)xValueOfInsertion 的值如果等于portMAX_DELAY ,那么就是在列表的最末尾进行插入,因为列表初始化时的xListEnd 的xItemValue 值为portMAX_DELAY
(4)pxIterator 是一个列表项指针,如果是在最末尾插入那么pxIterator 就指向要插入列表的迷你列表项的列表项值的地址,也就是下图中的位置
(5)如果不是末尾也就是代码中else代码那么就还是从列表的迷你列表项地址开始遍历(上图箭头指向位置),
pxIterator = ( ListItem_t * )&( pxList->xListEnd );
假如现在列表里面有两个列表项,遍历的条件就是下一个列表项的列表项值与要插入的列表项的列表项值进行比较,
pxIterator->pxNext->xItemValue <=xValueOfInsertion;
也就是下图指向的值与要插入的值进行比较
如果要插入项的项值比上图中的值小或等于上图中的值,那么
pxIterator = pxIterator->pxNext
pxIterator 指针就指向上图中的位置
依次循环
(6)的代码就是将要插入项中的指针指向进行改变,对着代码看下图
(7)是指定列表项的列表,(8)是插入完成后列表的列表项个数加1。
后面的尾插入、删除思路分析方法与此类似