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("/*******************列表和列表项地址*******************/
    ");
        printf("项目                                    地址                    
    ");
        printf("test_list                              %#x                    
    ",(int)&test_list);
        printf("test_list->pxIndex                     %#x                    
    ",(int)test_list.pxIndex);
        printf("test_list->xListEnd                    %#x                    
    ",(int)(&test_list.xListEnd));
        printf("test_listItem1                         %#x                    
    ",(int)&test_listItem1);
        printf("test_listItem2                         %#x                    
    ",(int)&test_listItem2);
        printf("test_listItem3                         %#x                    
    ",(int)&test_listItem3);
        printf("/************************结束**************************/
    
    ");
    
        vListInsert(&test_list, &test_listItem1);    //插入列表项test_listItem1
        vListInsert(&test_list, &test_listItem2);    //插入列表项test_listItem2
        vListInsert(&test_list,&test_listItem3);     //插入列表项test_listItem3
        printf("/******************添加列表项test_listItem123*****************/
    ");
        printf("项目                                    地址                    
    ");
        printf("test_list->xListEnd->pxNext            %#x                    
    ",(int)(test_list.xListEnd.pxNext));
        printf("test_listItem1->pxNext                 %#x                    
    ",(int)(test_listItem1.pxNext));
        printf("test_listItem2->pxNext                 %#x                    
    ",(int)(test_listItem2.pxNext));
        printf("test_listItem3->pxNext                 %#x                    
    ",(int)(test_listItem3.pxNext));
        printf("/*******************前后向连接分割线********************/
    ");
        printf("test_list->xListEnd->pxPrevious        %#x                    
    ",(int)(test_list.xListEnd.pxPrevious));
        printf("test_listItem1->pxPrevious             %#x                    
    ",(int)(test_listItem1.pxPrevious));
        printf("test_listItem2->pxPrevious             %#x                    
    ",(int)(test_listItem2.pxPrevious));
        printf("test_listItem3->pxPrevious             %#x                    
    ",(int)(test_listItem3.pxPrevious));
        printf("/************************结束**************************/
    
    ");
        
        uxListRemove(&test_listItem2);                //删除列表项test_listItem2
        printf("/******************删除列表项test_listItem2*****************/
    ");
        printf("项目                                    地址                    
    ");
        printf("test_list->xListEnd->pxNext            %#x                    
    ",(int)(test_list.xListEnd.pxNext));
        printf("test_listItem1->pxNext                 %#x                    
    ",(int)(test_listItem1.pxNext));
        printf("test_listItem3->pxNext                 %#x                    
    ",(int)(test_listItem3.pxNext));
        printf("/*******************前后向连接分割线********************/
    ");
        printf("test_list->xListEnd->pxPrevious        %#x                    
    ",(int)(test_list.xListEnd.pxPrevious));
        printf("test_listItem1->pxPrevious             %#x                    
    ",(int)(test_listItem1.pxPrevious));
        printf("test_listItem3->pxPrevious             %#x                    
    ",(int)(test_listItem3.pxPrevious));
        printf("/************************结束**************************/
    
    ");
    
        test_list.pxIndex=test_list.pxIndex->pxNext;    //pxIndex向后移一项,这样pxIndex就会指向ListItem1。
        vListInsertEnd(&test_list,&test_listItem2);     //列表末尾添加列表项ListItem2
        printf("/******************添加列表项test_listItem2*****************/
    ");
        printf("项目                                   地址                    
    ");
        printf("test_list->xListEnd->pxNext            %#x                    
    ",(int)(test_list.xListEnd.pxNext));
        printf("test_listItem2->pxNext                 %#x                    
    ",(int)(test_listItem2.pxNext));
        printf("test_listItem1->pxNext                 %#x                    
    ",(int)(test_listItem1.pxNext));
        printf("test_listItem3->pxNext                 %#x                    
    ",(int)(test_listItem3.pxNext));
        printf("/*******************前后向连接分割线********************/
    ");
        printf("test_list->xListEnd->pxPrevious        %#x                    
    ",(int)(test_list.xListEnd.pxPrevious));
        printf("test_listItem2->pxPrevious             %#x                    
    ",(int)(test_listItem2.pxPrevious));
        printf("test_listItem1->pxPrevious             %#x                    
    ",(int)(test_listItem1.pxPrevious));
        printf("test_listItem3->pxPrevious             %#x                    
    ",(int)(test_listItem3.pxPrevious));
        printf("/************************结束**************************/
    
    ");
    }
  •  打印信息为:
    /*******************列表和列表项地址*******************/
    项目                                       地址                    
    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                    
    /************************结束**************************/
原文地址:https://www.cnblogs.com/icefree/p/8689313.html