结构体定义
/*链表结构体*/
typedef struct xLIST
{
listFIRST_LIST_INTEGRITY_CHECK_VALUE /*用于链表完整性检查*/
configLIST_VOLATILE UBaseType_t uxNumberOfItems; /*记录链表项数目*/
ListItem_t * configLIST_VOLATILE pxIndex; /*用于遍历链表,初始化会指向最后的链表项,这里需要注意使用了volatile关键字,表明该指针可能会在其他地方修改*/
MiniListItem_t xListEnd;/*用于标记链表尾*/
listSECOND_LIST_INTEGRITY_CHECK_VALUE /*用于链表完整性检查*/
} List_t;
/*链表项结构体*/
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; /*指向结构体控制块*/
void * configLIST_VOLATILE pvContainer;/*指向该链表项对应的链表*/
listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE /*用于链表完整性检查*/
};
/*迷你链表项结构体*/
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;
};
根据定义可以看出以下几点:
- 链表结构是一个双向链表。
- 每个链表都由链表和链表项组成。
- 链表结构体本身有一个迷你链表项,用来标记链表的结尾。
链表和链表项初始化
/*链表初始化*/
void vListInitialise( List_t * const pxList )
{
/*将链表的Index索引指针指向自身的迷你链表项,即链表结尾*/
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;
/*初始化链表的完整性检查值*/
listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );
listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
}
/*链表项初始化*/
void vListInitialiseItem( ListItem_t * const pxItem )
{
/*确保该链表项没有被链表使用,往往初始化链表项之后就会进行插入或设置操作*/
pxItem->pvContainer = NULL;
/*初始化完整性检查*/
listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem );
}
链表的操作
链表的插入会根据List Item Value进行升序排列,其他并没有什么特殊的地方。初始化并插入两个节点后大概的数据结构,如下图所示:
从图中可以看出,List初始化并添加节点后,List Item 1/List Item 2 和 List自己的xListEnd节点一起组成了一个双向循环的链表。
Q&A
1).如何完成链表的完整性检查?
如果打开了完整性检查的开关(configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES),每个链表和链表项结构都会定义listFIRST_LIST_INTEGRITY_CHECK_VALUE和listSECOND_LIST_INTEGRITY_CHECK_VALUE(mini链表项没有定义这个),该定义是一个16位或32位的整形数,在链表或链表项初始化的时候会将该变量初始化为0x5a5a或0x5a5a5a5a,在检查的时候如果这两个变量都没有改变则通过完整性检查,否则认为链表被破坏。
2).如何使用List?
- 必须先定义一个List_t的全局变量,比如Timer中的 xActiveTimerList1
- 每一个节点结构体必须包含xLIST_ITEM类型的成员。
- 初始化链表后,将含有List Item成员的数据结构按照链表项值的大小插入到链表中,比如Timer中利用该值溢出的判断。
- 设置好pvOwner指针,后续可以根据该指针反向找到该节点的具体结构,如Timer_t。