FreeRTOS学习:一任务列表
发布时间
阅读量:
阅读量
FreeRTOS学习之路一:任务列表
在FreeRTOS环境中,任务列表扮演着至关重要的角色。深入理解任务列表中各节点所代表的具体意义,对于掌握FreeRTOS具有重要意义。双向列表 在FreeRTOS环境中完成的任务列表实际上是基于双向链表结构进行操作的。如图所示。

下面来慢慢看链表中的根节点以后任务节点都包含什么信息。
任务节点:
struct xLIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*暂时不用管这个宏,用来进行完整性判断*/
configLIST_VOLATILE TickType_t xItemValue; /*根据这个进行排序链表排序,这个值是由任务的延时时间决定*/
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*指向下一个节点*/
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*指向前一个节点 */
void * pvOwner; /*指向TCP任务控制块,这个任务控制块会将任务主体,任务栈,任务列表联系起来,后续都是操控任务控制块来完成任务调度 */
struct xLIST * configLIST_VOLATILE pxContainer; /*指向此节点所在的链表,也就是指向根节点 */
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*暂时不用管这个宏,用来进行完整性判断*/
};
typedef struct xLIST_ITEM ListItem_t; /* 重定义数据类型 */*
c

根节点:
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*< 暂时不用管这个宏,用来进行完整性判断*/
volatile UBaseType_t uxNumberOfItems; /*< 链表节点计数器,判断此条链表有多少个任务节点*/
ListItem_t * configLIST_VOLATILE pxIndex; /*<链表节点索引指针,可以用来遍历根节点下的任务节点*/
MiniListItem_t xListEnd; /*< 精简节点,这个就是链表的第一个精简节点 */
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*< 暂时不用管这个宏,用来进行完整性判断*/
} List_t;
c
精简节点:
struct xMINI_LIST_ITEM
{
listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE /*< 暂时不用管这个宏,用来进行完整性判断 */
configLIST_VOLATILE TickType_t xItemValue; /*根据这个值进行排序节点排序*/
struct xLIST_ITEM * configLIST_VOLATILE pxNext; /*指向下一个节点*/
struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*指向前一个节点 */
};
typedef struct xMINI_LIST_ITEM MiniListItem_t;
c
下面就放个图给大家看看这个三个节点是如何联系的

最后三个任务节点实际上是链表的第一个节点的不同表现形式,在这种情况下实际上根节点已经包含了精简节点的内容无需过多纠结
void vListInitialise( List_t * const pxList )
{
/* 将链表索引指针指向最后一个节点,也就是将索引指针指向根节点内部的精简节点 */
pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );
/* 将链表最后一个节点的辅助排序的值设置为最大,初始化该节点为链表最后一个节点,portMAX_DELAY是个宏,被设置为0xffffffffUL*/
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;
/* 下面两个宏不用管,还是用于完整性判断 */
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
c

最后初始化完成如下图

插入一个节点到空链表中:
void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t * const pxIndex = pxList->pxIndex;
/* 下面两个宏不用管 */
listTEST_LIST_INTEGRITY( pxList );
listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
/* 1将新节点的下一节点指针指向根节点的索引指针,也就是精简节点,此链表是一个环形链表,尾的后指针指向头,头的前指针指向尾 */
pxNewListItem->pxNext = pxIndex;
/*2 由于此时只有一个任务节点和根节点,所以任务节点的前指针也指向精简节点 */
pxNewListItem->pxPrevious = pxIndex->pxPrevious;
/* 不用管这个宏 */
mtCOVERAGE_TEST_DELAY();
/* 3精简节点的后指针指向插进来的任务节点 */
pxIndex->pxPrevious->pxNext = pxNewListItem;
/* 4精简节点的前指针指向插进来的任务节点 */
pxIndex->pxPrevious = pxNewListItem;
/* 5记住该节点所在链表的根节点 */
pxNewListItem->pxContainer = pxList;
/* 6节点计数器加一 */
( pxList->uxNumberOfItems )++;
}
c

根据注释中的步骤可以和下图比对。

按顺序将节点依次加入链表中
如果存在两个具有相同值的节点,则新的节点会被旧的节点之后加入
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; 1
pxNewListItem->pxNext->pxPrevious = pxNewListItem; 2
pxNewListItem->pxPrevious = pxIterator; 3
pxIterator->pxNext = pxNewListItem; 4
/*5记住该节点所在的链表 */
pxNewListItem->pvContainer = ( void * ) pxList;
/*6节点计数器加一*/
( pxList->uxNumberOfItems )++;
}
c


[1]: 参考《FreeRTOS 内核实现与应用开发实战指南 》
全部评论 (0)
还没有任何评论哟~
