1. 程式人生 > >FreeRTOS數據結構(一)--鏈表和鏈表項

FreeRTOS數據結構(一)--鏈表和鏈表項

set 開關 部分 添加 use XP prev inf ext

結構體定義

/*鏈表結構體*/
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;
};

根據定義可以看出以下幾點:

  1. 鏈表結構是一個雙向鏈表。
  2. 每個鏈表都由鏈表和鏈表項組成。
  3. 鏈表結構體本身有一個迷你鏈表項,用來標記鏈表的結尾。

鏈表和鏈表項初始化

/*鏈表初始化*/
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_VALUElistSECOND_LIST_INTEGRITY_CHECK_VALUE

(mini鏈表項沒有定義這個),該定義是一個16位或32位的整形數,在鏈表或鏈表項初始化的時候會將該變量初始化為0x5a5a或0x5a5a5a5a,在檢查的時候如果這兩個變量都沒有改變則通過完整性檢查,否則認為鏈表被破壞。

2).如何使用List?

  1. 必須先定義一個List_t的全局變量,比如Timer中的 xActiveTimerList1
  2. 每一個節點結構體必須包含xLIST_ITEM類型的成員。
  3. 初始化鏈表後,將含有List Item成員的數據結構按照鏈表項值的大小插入到鏈表中,比如Timer中利用該值溢出的判斷。
  4. 設置好pvOwner指針,後續可以根據該指針反向找到該節點的具體結構,如Timer_t。

FreeRTOS數據結構(一)--鏈表和鏈表項