3、列表和列表項


1.列表

  • 列表是FreeRTOSde中的一個數據結構,概念上和鏈表雷士,列表被用來跟蹤FreeRTOS中的任務,與列表相關的全放在list.c和list.h中,在list.h中定義了一個結構體如下:
    typedef struct xLIST
    {
        listFIRST_LIST_INTEGRITY_CHECK_VALUE                //用來檢查列表的完整性
        configLIST_VOLATILE UBaseType_t uxNumberOfItems;   //用來記錄列表中列表項的數量  
        ListItem_t * configLIST_VOLATILE pxIndex;           //用來記錄當前列表項索引號,用於遍歷列表
        MiniListItem_t xListEnd;                            //列表中最后一個列表項,用來表示列表結束,,這是一個mini列表項
        listSECOND_LIST_INTEGRITY_CHECK_VALUE               //用來檢查列表的完整性
     } List_t;

2.列表項

  • 列表項就是存放在列表中的項目,FreeRTOS提供了兩種列表項:列表項和迷你列表項,定義在list.h文件中;
  • 列表項,跟雙鏈表相似
    struct xLIST_ITEM
    {
        listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE            //檢查列表的完整性
        configLIST_VOLATILE TickType_t xItemValue;           //列表項值
        struct xLIST_ITEM * configLIST_VOLATILE pxNext;      //pxNext指向下一個列表項
        struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;  //pxPrevious指向前一個列表項
        void * pvOwner;                                      //記錄此列表項歸誰擁有,通常是任務控制塊
        void * configLIST_VOLATILE pvContainer;              //用來記錄此列表項歸哪個列表
        listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE           //檢查列表的完整性
    };
    typedef struct xLIST_ITEM ListItem_t;
  • 迷你列表項,定義在list.h文件中,如下:
    struct xMINI_LIST_ITEM
    {
        listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE            //檢查迷你列表項的完整性
        configLIST_VOLATILE TickType_t xItemValue;           //記錄列表項的值
        struct xLIST_ITEM * configLIST_VOLATILE pxNext;      //pxNext指向下一個列表項
        struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;  //pxPrevious指向上一個列表項
    };
    typedef struct xMINI_LIST_ITEM MiniListItem_t;
  • 列表項和迷你列表項的區別:迷你列表項別列表項少了幾個成員變量;在有些情況下我們不需要列表項這么全的功能,可能只需其中的幾個成員變量,如果此時使用列表項的話會造成內存浪費;

3.列表初始化

  • 列表的初始化其實是初始化列表結構體List_t中的各個成員變量,列表通過vListInitialse()來完成,定於於list.c中
    void vListInitialise( List_t * const pxList )
    {
        pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );            //xListEnd用來表示列表的末尾,pxIndex表示列表項的索引號
        pxList->xListEnd.xItemValue = portMAX_DELAY;                         //xListEnd根據MCU不同,值也不同,stm32為32位,所以 XListEnd為oxffffffffUL
        pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );    //初始化列表項xListEnd的pxNext變量
        pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );//初始化列表項xListEnd的pxPrevious變量,指向xListEnd自身
        pxList->uxNumberOfItems = ( UBaseType_t ) 0U;                        //此時沒有其他列表項,因此值為0(這里沒有算xListEnd)
        listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );                      //初始化列表項中用於完整性檢查的字段,不同MCU值不同,32位系統為0x5a5a5a5aUL
        listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );                      //初始化列表項中用於完整性檢查的字段,不同MCU值不同,32位系統為0x5a5a5a5aUL

4.列表項初始化

  • 列表項的初始化是通過vListInitialiseItem()來完成,定於於list.c中
    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 );}
  • 列表項的初始化比較簡單,只需要將pvContainer的初始值設為NULL,並且給完整性檢查的變量賦值即可;

5.列表項插入

  • 列表項插入分為:頭插入和尾插入。

頭插入

  • 通過函數VListInert()來完成,函數原型為:
    void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem ) //pxList:需要插入的列表, pxNewListItem:需要插入的列表項
  • 列表項的插入過程如圖所示:

   

尾插入

  • 通過函數vListInsertEnd()來實現,函數原型為:
    void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem ) //pxList:列表項要插入的列表, pxNewListItem:要插入的列表項
  •  尾插入過程如下圖所示:

6.列表項的刪除 

  •  列表項的刪除是通過uxListRemove()函數來完成的,函數原型為:
    UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove ) 
       //pxItemToRemove:要刪除的列表項

7.列表的遍歷

  •  列表的遍歷是通過listGET_OWNER_OF_NEXT_ENTRY()函數來實現的,每調用一次這個函數,列表的pxIndex變量就會指向下一個列表項,並返回這個列表項的pxOwner變量值,函數原型如下:
    //pxTCB:用來保存pxIndex所指向的列表項的pvOwner變量值
    //pxList:變量指向下一個列表項
    #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )

8.程序驗證

  •  部分程序如下所示:
    //list_task 任務
    void list_task(void *pvParameters);       // 任務函數
    #define list_task_zise 300                // 任務堆棧的大小
    #define list_task_prio 3                  // 任務優先級
    TaskHandle_t list_task_handler;           // 任務句柄
    
    // 定義一個列表和一個列表項
    List_t test_list;                         //定義一個列表
    ListItem_t test_listItem1;                //定義一個列表項test_listItem1
    ListItem_t test_listItem2;                //定義一個列表項test_listItem2
    ListItem_t test_listItem3;                //定義一個列表項test_listItem3
    
    void start_task( void * pvParameters )
    {
        taskENTER_CRITICAL();    // 創建臨界區
        // 創建led1任務
        xTaskCreate((TaskFunction_t    )led1_task,
                    (const char *     )"led1_task",
                    (uint16_t        )start_task_zise,
                    (void *            )NULL,
                    (UBaseType_t    )led1_task_prio,
                    (TaskHandle_t * )&led1_task_handler);
        
        // 創建led2任務            
        xTaskCreate((TaskFunction_t    )list_task,
                    (const char *     )"list_task",
                    (uint16_t        )list_task_zise,
                    (void *            )NULL,
                    (UBaseType_t    )list_task_prio,
                    (TaskHandle_t * )&list_task_handler);
        vTaskDelete(start_task_handler); //刪除開始任務
        taskEXIT_CRITICAL();    // 退出臨界區
    }
    
    //list任務函數 
    void list_task( void * pvParameters )
    {
        vListInitialise(&test_list);             //初始化列表
        vListInitialiseItem(&test_listItem1);    //初始化列表項
        vListInitialiseItem(&test_listItem2);    //初始化列表項
        vListInitialiseItem(&test_listItem3);    //初始化列表項
        
        test_listItem1.xItemValue = 40;          //設置test_listItem1列表項值為40
        test_listItem2.xItemValue = 50;          //設置test_listItem2列表項值為50
        test_listItem3.xItemValue = 60;          //設置test_listItem3列表項值為60
        
        // 打印列表和其他列表項的地址
        printf("/*******************列表和列表項地址*******************/\r\n");
        printf("項目                                    地址                    \r\n");
        printf("test_list                              %#x                    \r\n",(int)&test_list);
        printf("test_list->pxIndex                     %#x                    \r\n",(int)test_list.pxIndex);
        printf("test_list->xListEnd                    %#x                    \r\n",(int)(&test_list.xListEnd));
        printf("test_listItem1                         %#x                    \r\n",(int)&test_listItem1);
        printf("test_listItem2                         %#x                    \r\n",(int)&test_listItem2);
        printf("test_listItem3                         %#x                    \r\n",(int)&test_listItem3);
        printf("/************************結束**************************/\r\n\r\n");
    
        vListInsert(&test_list, &test_listItem1);    //插入列表項test_listItem1
        vListInsert(&test_list, &test_listItem2);    //插入列表項test_listItem2
        vListInsert(&test_list,&test_listItem3);     //插入列表項test_listItem3
        printf("/******************添加列表項test_listItem123*****************/\r\n");
        printf("項目                                    地址                    \r\n");
        printf("test_list->xListEnd->pxNext            %#x                    \r\n",(int)(test_list.xListEnd.pxNext));
        printf("test_listItem1->pxNext                 %#x                    \r\n",(int)(test_listItem1.pxNext));
        printf("test_listItem2->pxNext                 %#x                    \r\n",(int)(test_listItem2.pxNext));
        printf("test_listItem3->pxNext                 %#x                    \r\n",(int)(test_listItem3.pxNext));
        printf("/*******************前后向連接分割線********************/\r\n");
        printf("test_list->xListEnd->pxPrevious        %#x                    \r\n",(int)(test_list.xListEnd.pxPrevious));
        printf("test_listItem1->pxPrevious             %#x                    \r\n",(int)(test_listItem1.pxPrevious));
        printf("test_listItem2->pxPrevious             %#x                    \r\n",(int)(test_listItem2.pxPrevious));
        printf("test_listItem3->pxPrevious             %#x                    \r\n",(int)(test_listItem3.pxPrevious));
        printf("/************************結束**************************/\r\n\r\n");
        
        uxListRemove(&test_listItem2);                //刪除列表項test_listItem2
        printf("/******************刪除列表項test_listItem2*****************/\r\n");
        printf("項目                                    地址                    \r\n");
        printf("test_list->xListEnd->pxNext            %#x                    \r\n",(int)(test_list.xListEnd.pxNext));
        printf("test_listItem1->pxNext                 %#x                    \r\n",(int)(test_listItem1.pxNext));
        printf("test_listItem3->pxNext                 %#x                    \r\n",(int)(test_listItem3.pxNext));
        printf("/*******************前后向連接分割線********************/\r\n");
        printf("test_list->xListEnd->pxPrevious        %#x                    \r\n",(int)(test_list.xListEnd.pxPrevious));
        printf("test_listItem1->pxPrevious             %#x                    \r\n",(int)(test_listItem1.pxPrevious));
        printf("test_listItem3->pxPrevious             %#x                    \r\n",(int)(test_listItem3.pxPrevious));
        printf("/************************結束**************************/\r\n\r\n");
    
        test_list.pxIndex=test_list.pxIndex->pxNext;    //pxIndex向后移一項,這樣pxIndex就會指向ListItem1。
        vListInsertEnd(&test_list,&test_listItem2);     //列表末尾添加列表項ListItem2
        printf("/******************添加列表項test_listItem2*****************/\r\n");
        printf("項目                                   地址                    \r\n");
        printf("test_list->xListEnd->pxNext            %#x                    \r\n",(int)(test_list.xListEnd.pxNext));
        printf("test_listItem2->pxNext                 %#x                    \r\n",(int)(test_listItem2.pxNext));
        printf("test_listItem1->pxNext                 %#x                    \r\n",(int)(test_listItem1.pxNext));
        printf("test_listItem3->pxNext                 %#x                    \r\n",(int)(test_listItem3.pxNext));
        printf("/*******************前后向連接分割線********************/\r\n");
        printf("test_list->xListEnd->pxPrevious        %#x                    \r\n",(int)(test_list.xListEnd.pxPrevious));
        printf("test_listItem2->pxPrevious             %#x                    \r\n",(int)(test_listItem2.pxPrevious));
        printf("test_listItem1->pxPrevious             %#x                    \r\n",(int)(test_listItem1.pxPrevious));
        printf("test_listItem3->pxPrevious             %#x                    \r\n",(int)(test_listItem3.pxPrevious));
        printf("/************************結束**************************/\r\n\r\n");
    }
  •  打印信息為:
    /*******************列表和列表項地址*******************/
    項目                                       地址                    
    test_list                              0x200000b4                    
    test_list->pxIndex                     0x200000bc                    
    test_list->xListEnd                    0x200000bc                    
    test_listItem1                         0x200000c8                    
    test_listItem2                         0x200000dc                    
    test_listItem3                         0x200000f0                    
    /************************結束**************************/
    
    /******************添加列表項test_listItem123*****************/
    項目                                       地址                    
    test_list->xListEnd->pxNext            0x200000c8                    
    test_listItem1->pxNext                 0x200000dc                    
    test_listItem2->pxNext                 0x200000f0                    
    test_listItem3->pxNext                 0x200000bc                    
    /*******************前后向連接分割線********************/
    test_list->xListEnd->pxPrevious        0x200000f0                    
    test_listItem1->pxPrevious             0x200000bc                    
    test_listItem2->pxPrevious             0x200000c8                    
    test_listItem3->pxPrevious             0x200000dc                    
    /************************結束**************************/
    
    /******************刪除列表項test_listItem2*****************/
    項目                                       地址                    
    test_list->xListEnd->pxNext            0x200000c8                    
    test_listItem1->pxNext                 0x200000f0                    
    test_listItem3->pxNext                 0x200000bc                    
    /*******************前后向連接分割線********************/
    test_list->xListEnd->pxPrevious        0x200000f0                    
    test_listItem1->pxPrevious             0x200000bc                    
    test_listItem3->pxPrevious             0x200000c8                    
    /************************結束**************************/
    
    /******************添加列表項test_listItem2*****************/
    項目                                       地址                    
    test_list->xListEnd->pxNext            0x200000dc                    
    test_listItem2->pxNext                 0x200000c8                    
    test_listItem1->pxNext                 0x200000f0                    
    test_listItem3->pxNext                 0x200000bc                    
    /*******************前后向連接分割線********************/
    test_list->xListEnd->pxPrevious        0x200000f0                    
    test_listItem2->pxPrevious             0x200000bc                    
    test_listItem1->pxPrevious             0x200000dc                    
    test_listItem3->pxPrevious             0x200000c8                    
    /************************結束**************************/

     


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM