精华内容
下载资源
问答
  • FreeRTOS高级篇1---FreeRTOS列表和列表项

    万次阅读 多人点赞 2016-04-19 14:34:13
    我们在这一章集中讲解列表和列表项的结构以及操作函数,在下一章讲解任务创建时,会用到本章的知识点。 列表被FreeRTOS调度器使用,用于跟踪任务,处于就绪、挂起、延时的任务,都会被挂接到各自的列表中。

          FreeRTOS内核调度大量使用了列表(list)和列表项(list item)数据结构。我们如果想一探FreeRTOS背后的运行机制,首先遇到的拦路虎就是列表和列表项。对于FreeRTOS内核来说,列表就是它最基础的部分。我们在这一章集中讲解列表和列表项的结构以及操作函数,在下一章讲解任务创建时,会用到本章的知识点。

          列表被FreeRTOS调度器使用,用于跟踪任务,处于就绪、挂起、延时的任务,都会被挂接到各自的列表中。用户程序如果有需要,也可以使用列表。

          FreeRTOS列表使用指针指向列表项。一个列表(list)下面可能有很多个列表项(list item),每个列表项都有一个指针指向列表。如图1-1所示。

     

    图1-1:列表与列表项

          列表项有两种形式,全功能版的列表项xLIST_ITEM和迷你版的列表项xMINI_LIST_ITEM。我们来看一下它们具体的定义,先看全功能版。

     

    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;                                     /*指向一个任务TCB*/
         void * configLIST_VOLATILE pvContainer;             /*指向包含该列表项的列表 */
         listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          /*用于检测列表项数据是否完整*/
    };
    typedef struct xLIST_ITEM ListItem_t;

     

          宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE用于检查列表项数据是否完整,在projdefs.h中,如果将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE会被两个已知的数值代替。

          xItemValue是列表项值,通常是一个被跟踪的任务优先级或是一个调度事件的计数器值。如果任务因为等待从队列取数据而进入阻塞状态,则任务的事件列表项的列表项值保存任务优先级有关信息,状态列表项的列表项值保存阻塞时间有关的信息。这个变量被configLIST_VOLATILE修饰,configLIST_VOLATILE被映射成C语言关键字volatile,表明这个变量是“易变的”,告诉编译器不得对这个变量进行代码优化,因为列表项的成员可能会在中断服务程序中被更新。关于volatile关键字,如果不是熟悉的话,可以参考我的博文《编写优质嵌入式C程序》第3.2.4节。

          pxNext和pxPrevious是列表项类型指针,用来指向列表中下一个和上一个列表项,通过这两个指针,列表项之间可以形成类似双向链表结构。

          指针pvOwner通常指向一个任务TCB。

          指针pvContainer指向包含该列表项的列表。

          迷你版的列表项xMINI_LIST_ITEM是全功能版列表项xLIST_ITEM的一个子集,定义如下所示:

     

    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;

     

             既然有了全功能版的列表项,为什么还要声明迷你版的列表项呢?这是因为列表结构体需要一个列表项成员,但又不需要列表项中的所有字段,所以才有了迷你版列表项。列表结构体定义为:

     

    typedef struct xLIST
    {
         listFIRST_LIST_INTEGRITY_CHECK_VALUE                        /*用于检测列表项数据是否完整*/
         configLIST_VOLATILE UBaseType_t uxNumberOfItems;
         ListItem_t * configLIST_VOLATILE pxIndex;                   /*用于遍历列表*/
         MiniListItem_t xListEnd;                                    /*列表项*/
         listSECOND_LIST_INTEGRITY_CHECK_VALUE                       /*用于检测列表项数据是否完整*/
    }List_t;

     

          和列表项定义相同,宏listFIRST_LIST_INTEGRITY_CHECK_VALUE和listSECOND_LIST_INTEGRITY_CHECK_VALUE用于检查列表项数据是否完整,在projdefs.h中,如果将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE会被两个已知的数值代替。

          uxNumberOfItems表示该列表中挂接的列表项数目,0表示列表为空。

          列表项类型指针用于遍历列表,列表初始化后,这个指针指向&xListEnd。通过宏listGET_OWNER_OF_NEXT_ENTRY()来获取列表中的下一个列表项。

          列表项xListEnd用于标记列表结束。xListEnd.xItemValue被初始化为一个常数,其值与硬件架构相关,为0xFFFF(16位架构)或者0xFFFFFFFF(32位架构)。

          下面我们看一下列表操作。FreeROTS提供了几个API函数,用于初始化列表和列表项以及列表项插入操作。

    1.初始化列表

          列表结构体中包含一个列表项成员,主要用于标记列表结束。初始化列表就是把这个列表项插入到列表中。
    void vListInitialise( List_t * const pxList )
    {
         /*列表索引指向列表项*/
         pxList->pxIndex = ( ListItem_t * )&( pxList->xListEnd );                  
         /* 设置为最大可能值 */
         pxList->xListEnd.xItemValue =portMAX_DELAY;
     
         /* 列表项xListEnd的pxNext和pxPrevious指针指向了它自己 */
         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 );
    }

          如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listSET_LIST_INTEGRITY_CHECK_1_VALUE()和listSET_LIST_INTEGRITY_CHECK_2_VALUE被一个已知值代替,默认为0x5a5a(16位架构)或者0x5a5a5a5a(32位架构)。

          假设禁止列表数据完整性检查,初始化后的列表如图1-2所示,uxNumberOfItems被初始化为0,xListEnd.xItemValue初始化为0xffffffff,pxIndex、xListEnd.pxNext和xListEnd.pxPrevious初始化为指向列表项xListEnd。

     

    图1-2:初始化后的列表

    2.初始化列表项

          列表项的初始比较简单,只要确保列表项不在任何列表中即可。

     

    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 );
    }

     

          如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE会被两个已知的数值代替,默认为0x5a5a(16位架构)或者0x5a5a5a5a(32位架构)。

          假设禁止列表项数据完整性检查,初始化后的列表项如图1-3所示。仅是将指针pvContainer设置为空指针,该指针用于指向包含该列表项的列表,这里设置为NULL表示这个列表项不属于任何列表。

     

    图1-3:初始化后的列表项

    3.将列表项插入到列表中,列表项所在的位置取决于列表项的列表项值(xItemValue)。

          每个列表项对象都有一个列表项值(xItemValue),通常是一个被跟踪的任务优先级或是一个调度事件的计数器值。调用API函数vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem)可以将pxNewListItem指向的列表项插入到pxList指向的列表中,列表项在列表的位置由pxNewListItem->xItemValue决定,按照升序排列。

     

    void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
    {
    ListItem_t *pxIterator;
    const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
     
             /* 检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/
             listTEST_LIST_INTEGRITY( pxList );
             listTEST_LIST_ITEM_INTEGRITY(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;
             pxNewListItem->pxNext->pxPrevious= pxNewListItem;
             pxNewListItem->pxPrevious =pxIterator;
             pxIterator->pxNext = pxNewListItem;
     
             pxNewListItem->pvContainer = ( void* ) pxList;
     
             ( pxList->uxNumberOfItems )++;
    }

     

          根据xItemValue的值将新的列表项插入到列表。如果列表中存在与新列表项xItemValue值相同的列表项,则新插入的列表项位于它之后。如果列表项的xItemValue值等于portMAX_DELAY(列表结束标记,我们在讲列表数据结构时,说到每个列表数据结构体中都有一个列表项成员xListEnd,用于标记列表结束。xListEnd.xItemValue被初始化为一个常数,其值与硬件架构相关,为0xFFFF或者0xFFFFFFFF。这个常数在移植层定义,即宏portMAX_DELAY),则表示到达了列表结束位置。

          我们用图示的方法来讲解这个函数,我们假设一个列表项值(xItemValue)为32的列表项插入到如图1-2所示的初始化后的列表中,调用vListInsert()函数后,列表和列表项的关系如图1-4所示。列表项xListItem_1的成员指针pxNext和pxPrevious都指向了xListEnd,而xListEnd的成员指针pxNext和pxPrevious都指向了列表项xListItem_1;列表项xListItem_1的成员指针pvContainer指向了列表xList_1;列表成员uxNumberOfItems为1。

     

    图1-4:将列表项插入到列表

          在此基础上,如果再将一个列表项值xItemValue)为40的列表项插入到列表中,调用vListInsert()函数后,列表和列表项的关系如图1-5所示。

     

    图1-5:将列表项插入到列表

     

    4.将列表项插入到列表末端

            第3节讲的API插入函数是根据列表项中的列表项值(xItemValue)来决定插入位置的,本节所讲的API函数vListInsertEnd()是简单的将列表项插入到列表的末端。在下一章任务创建分析的文章中,将会遇到这个API函数,到时再以图标的形式分析这个函数,现在给出这个函数的源码。

     

    void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
    {
    ListItem_t* const pxIndex = pxList->pxIndex;
     
             /*检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/
             listTEST_LIST_INTEGRITY( pxList );
             listTEST_LIST_ITEM_INTEGRITY(pxNewListItem );
     
             /*向列表中插入新的列表项*/
             pxNewListItem->pxNext = pxIndex;
             pxNewListItem->pxPrevious =pxIndex->pxPrevious;
     
             mtCOVERAGE_TEST_DELAY();
     
             pxIndex->pxPrevious->pxNext =pxNewListItem;
             pxIndex->pxPrevious = pxNewListItem;
     
             pxNewListItem->pvContainer = ( void* ) pxList;
     
             ( pxList->uxNumberOfItems )++;
    }

     

     

     

     

     

     

    展开全文
  • 列表和列表项

    千次阅读 2017-01-17 14:32:04
    FreeRTOS内核调度大量使用了列表(list)和列表项(list item)数据结构。我们如果想一探FreeRTOS背后的运行机制,首先遇到的拦路虎就是列表和列表项。对于FreeRTOS内核来说,列表就是它最基础的部分。我们在这一章...

      FreeRTOS内核调度大量使用了列表(list)和列表项(list item)数据结构。我们如果想一探FreeRTOS背后的运行机制,首先遇到的拦路虎就是列表和列表项。对于FreeRTOS内核来说,列表就是它最基础的部分。我们在这一章集中讲解列表和列表项的结构以及操作函数,在下一章讲解任务创建时,会用到本章的知识点。

          列表被FreeRTOS调度器使用,用于跟踪任务,处于就绪、挂起、延时的任务,都会被挂接到各自的列表中。用户程序如果有需要,也可以使用列表。

          FreeRTOS列表使用指针指向列表项。一个列表(list)下面可能有很多个列表项(list item),每个列表项都有一个指针指向列表。如图1-1所示。


    图1-1:列表与列表项

          列表项有两种形式,全功能版的列表项xLIST_ITEM和迷你版的列表项xMINI_LIST_ITEM。我们来看一下它们具体的定义,先看全功能版。

    [objc] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. struct xLIST_ITEM  
    2. {  
    3.      listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*用于检测列表项数据是否完整*/  
    4.      configLIST_VOLATILETickType_t xItemValue;           /*列表项值*/  
    5.      struct xLIST_ITEM * configLIST_VOLATILE pxNext;      /*指向列表中下一个列表项*/  
    6.      struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;  /*指向列表中上一个列表项*/  
    7.      voidvoid * pvOwner;                                     /*指向一个任务TCB*/  
    8.      voidvoid * configLIST_VOLATILE pvContainer;             /*指向包含该列表项的列表 */  
    9.      listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          /*用于检测列表项数据是否完整*/  
    10. };  
    11. typedef struct xLIST_ITEM ListItem_t;  

          宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE用于检查列表项数据是否完整,在projdefs.h中,如果将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE会被两个已知的数值代替。

          xItemValue是列表项值,通常是一个被跟踪的任务优先级或是一个调度事件的计数器值。如果任务因为等待从队列取数据而进入阻塞状态,则任务的事件列表项的列表项值保存任务优先级有关信息,状态列表项的列表项值保存阻塞时间有关的信息。这个变量被configLIST_VOLATILE修饰,configLIST_VOLATILE被映射成C语言关键字volatile,表明这个变量是“易变的”,告诉编译器不得对这个变量进行代码优化,因为列表项的成员可能会在中断服务程序中被更新。关于volatile关键字,如果不是熟悉的话,可以参考我的博文《编写优质嵌入式C程序》第3.2.4节。

          pxNext和pxPrevious是列表项类型指针,用来指向列表中下一个和上一个列表项,通过这两个指针,列表项之间可以形成类似双向链表结构。

          指针pvOwner通常指向一个任务TCB。

          指针pvContainer指向包含该列表项的列表。

          迷你版的列表项xMINI_LIST_ITEM是全功能版列表项xLIST_ITEM的一个子集,定义如下所示:

    [objc] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. struct xMINI_LIST_ITEM  
    2. {  
    3.      listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*用于检测列表项数据是否完整*/  
    4.      configLIST_VOLATILE TickType_t xItemValue;  
    5.      struct xLIST_ITEM * configLIST_VOLATILE pxNext;  
    6.      struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;  
    7. };  
    8. typedef struct xMINI_LIST_ITEM MiniListItem_t;  

             既然有了全功能版的列表项,为什么还要声明迷你版的列表项呢?这是因为列表结构体需要一个列表项成员,但又不需要列表项中的所有字段,所以才有了迷你版列表项。列表结构体定义为:

    [objc] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. typedef struct xLIST  
    2. {  
    3.      listFIRST_LIST_INTEGRITY_CHECK_VALUE                        /*用于检测列表项数据是否完整*/  
    4.      configLIST_VOLATILE UBaseType_t uxNumberOfItems;  
    5.      ListItem_t * configLIST_VOLATILE pxIndex;                   /*用于遍历列表*/  
    6.      MiniListItem_t xListEnd;                                    /*列表项*/  
    7.      listSECOND_LIST_INTEGRITY_CHECK_VALUE                       /*用于检测列表项数据是否完整*/  
    8. }List_t;  

          和列表项定义相同,宏listFIRST_LIST_INTEGRITY_CHECK_VALUE和listSECOND_LIST_INTEGRITY_CHECK_VALUE用于检查列表项数据是否完整,在projdefs.h中,如果将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE会被两个已知的数值代替。

          uxNumberOfItems表示该列表中挂接的列表项数目,0表示列表为空。

          列表项类型指针用于遍历列表,列表初始化后,这个指针指向&xListEnd。通过宏listGET_OWNER_OF_NEXT_ENTRY()来获取列表中的下一个列表项。

          列表项xListEnd用于标记列表结束。xListEnd.xItemValue被初始化为一个常数,其值与硬件架构相关,为0xFFFF(16位架构)或者0xFFFFFFFF(32位架构)。

          下面我们看一下列表操作。FreeROTS提供了几个API函数,用于初始化列表和列表项以及列表项插入操作。

    1.初始化列表

          列表结构体中包含一个列表项成员,主要用于标记列表结束。初始化列表就是把这个列表项插入到列表中。
    [objc] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. void vListInitialise( List_t * const pxList )  
    2. {  
    3.      /*列表索引指向列表项*/  
    4.      pxList->pxIndex = ( ListItem_t * )&( pxList->xListEnd );                    
    5.      /* 设置为最大可能值 */  
    6.      pxList->xListEnd.xItemValue =portMAX_DELAY;  
    7.    
    8.      /* 列表项xListEnd的pxNext和pxPrevious指针指向了它自己 */  
    9.      pxList->xListEnd.pxNext = (ListItem_t * ) &( pxList->xListEnd );  
    10.      pxList->xListEnd.pxPrevious= ( ListItem_t * ) &( pxList->xListEnd );  
    11.      pxList->uxNumberOfItems = ( UBaseType_t) 0U;  
    12.    
    13.      /* 设置为已知值,用于检测列表数据是否完整*/  
    14.      listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList );  
    15.      listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList );  
    16. }  

          如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listSET_LIST_INTEGRITY_CHECK_1_VALUE()和listSET_LIST_INTEGRITY_CHECK_2_VALUE被一个已知值代替,默认为0x5a5a(16位架构)或者0x5a5a5a5a(32位架构)。

          假设禁止列表数据完整性检查,初始化后的列表如图1-2所示,uxNumberOfItems被初始化为0,xListEnd.xItemValue初始化为0xffffffff,pxIndex、xListEnd.pxNext和xListEnd.pxPrevious初始化为指向列表项xListEnd。


    图1-2:初始化后的列表

    2.初始化列表项

          列表项的初始比较简单,只要确保列表项不在任何列表中即可。

    [objc] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. void vListInitialiseItem( ListItem_t * const pxItem )  
    2. {  
    3.      pxItem->pvContainer = NULL;  
    4.    
    5.      /*设置为已知值,用于检测列表项数据是否完整*/  
    6.      listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );  
    7.      listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );  
    8. }  

          如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,则使能列表项数据完整性检查,则宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE会被两个已知的数值代替,默认为0x5a5a(16位架构)或者0x5a5a5a5a(32位架构)。

          假设禁止列表项数据完整性检查,初始化后的列表项如图1-3所示。仅是将指针pvContainer设置为空指针,该指针用于指向包含该列表项的列表,这里设置为NULL表示这个列表项不属于任何列表。


    图1-3:初始化后的列表项

    3.将列表项插入到列表中,列表项所在的位置取决于列表项的列表项值(xItemValue)。

          每个列表项对象都有一个列表项值(xItemValue),通常是一个被跟踪的任务优先级或是一个调度事件的计数器值。调用API函数vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem)可以将pxNewListItem指向的列表项插入到pxList指向的列表中,列表项在列表的位置由pxNewListItem->xItemValue决定,按照降序排列。

    [objc] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )  
    2. {  
    3. ListItem_t *pxIterator;  
    4. const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;  
    5.    
    6.          /* 检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/  
    7.          listTEST_LIST_INTEGRITY( pxList );  
    8.          listTEST_LIST_ITEM_INTEGRITY(pxNewListItem );  
    9.    
    10.          /*将新的列表项插入到列表,根据xItemValue的值降序插入列表。*/  
    11.          if( xValueOfInsertion == portMAX_DELAY)  
    12.          {  
    13.                    pxIterator =pxList->xListEnd.pxPrevious;  
    14.          }  
    15.          else  
    16.          {  
    17.                    for( pxIterator = (ListItem_t * ) &( pxList->xListEnd );pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator =pxIterator->pxNext )  
    18.                    {  
    19.                             /* 这里为空 */  
    20.                    }  
    21.          }  
    22.    
    23.          pxNewListItem->pxNext =pxIterator->pxNext;  
    24.          pxNewListItem->pxNext->pxPrevious= pxNewListItem;  
    25.          pxNewListItem->pxPrevious =pxIterator;  
    26.          pxIterator->pxNext = pxNewListItem;  
    27.    
    28.          pxNewListItem->pvContainer = ( void* ) pxList;  
    29.    
    30.          ( pxList->uxNumberOfItems )++;  
    31. }  

          根据xItemValue的值将新的列表项插入到列表。如果列表中存在与新列表项xItemValue值相同的列表项,则新插入的列表项位于它之后。如果列表项的xItemValue值等于portMAX_DELAY(列表结束标记,我们在讲列表数据结构时,说到每个列表数据结构体中都有一个列表项成员xListEnd,用于标记列表结束。xListEnd.xItemValue被初始化为一个常数,其值与硬件架构相关,为0xFFFF或者0xFFFFFFFF。这个常数在移植层定义,即宏portMAX_DELAY),则表示到达了列表结束位置。

          我们用图示的方法来讲解这个函数,我们假设一个列表项值(xItemValue)为32的列表项插入到如图1-2所示的初始化后的列表中,调用vListInsert()函数后,列表和列表项的关系如图1-4所示。列表项xListItem_1的成员指针pxNext和pxPrevious都指向了xListEnd,而xListEnd的成员指针pxNext和pxPrevious都指向了列表项xListItem_1;列表项xListItem_1的成员指针pvContainer指向了列表xList_1;列表成员uxNumberOfItems为1。


    图1-4:将列表项插入到列表

          在此基础上,如果再将一个列表项值xItemValue)为40的列表项插入到列表中,调用vListInsert()函数后,列表和列表项的关系如图1-5所示。


    图1-5:将列表项插入到列表

     

    4.将列表项插入到列表末端

            第3节讲的API插入函数是根据列表项中的列表项值(xItemValue)来决定插入位置的,本节所讲的API函数vListInsertEnd()是简单的将列表项插入到列表的末端。在下一章任务创建分析的文章中,将会遇到这个API函数,到时再以图标的形式分析这个函数,现在给出这个函数的源码。

    [objc] view plain copy
     print?在CODE上查看代码片派生到我的代码片
    1. void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )  
    2. {  
    3. ListItem_t* const pxIndex = pxList->pxIndex;  
    4.    
    5.          /*检查列表和列表项数据的完整性,仅当configASSERT()定义时有效。*/  
    6.          listTEST_LIST_INTEGRITY( pxList );  
    7.          listTEST_LIST_ITEM_INTEGRITY(pxNewListItem );  
    8.    
    9.          /*向列表中插入新的列表项*/  
    10.          pxNewListItem->pxNext = pxIndex;  
    11.          pxNewListItem->pxPrevious =pxIndex->pxPrevious;  
    12.    
    13.          mtCOVERAGE_TEST_DELAY();  
    14.    
    15.          pxIndex->pxPrevious->pxNext =pxNewListItem;  
    16.          pxIndex->pxPrevious = pxNewListItem;  
    17.    
    18.          pxNewListItem->pvContainer = ( void* ) pxList;  
    19.    
    20.          ( pxList->uxNumberOfItems )++;  
    21. }  
    展开全文
  • FreeRTOS列表和列表项

    千次阅读 2017-09-05 20:39:55
    FreeRTOS 列表和列表项

    本文是《ALIENTEK STM32F429 FreeRTOS 开发教程》第七章学习笔记
    第一章笔记–FreeRTOS简介与源码下载
    第二章笔记–FreeRTOS在STM32F4上移植
    第三章笔记-FreeRTOS系统配置
    第四章笔记-FreeRTOS中断分析
    第四章笔记补充-FreeRTOS临界段代码
    第五章笔记-FreeRTOS任务基础
    第六章笔记-FreeRTOS任务API函数的使用

    1. 列表和列表项的简介

    1.1 列表

    列表是FreeRTOS中的一个数据结构,概念与链表有些类似,列表被用来跟踪FreeRTOS中的任务。与列表相关的全部代码在文件list.c和list.h中。

    list.h中定义了结构体List_t:

    typedef struct xLIST
    {
        listFIRST_LIST_INTEGRITY_CHECK_VALUE                /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
        configLIST_VOLATILE UBaseType_t uxNumberOfItems;
        ListItem_t * configLIST_VOLATILE pxIndex;           /*< Used to walk through the list.  Points to the last item returned by a call to listGET_OWNER_OF_NEXT_ENTRY (). */
        MiniListItem_t xListEnd;                            /*< List item that contains the maximum possible item value meaning it is always at the end of the list and is therefore used as a marker. */
        listSECOND_LIST_INTEGRITY_CHECK_VALUE               /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
    } List_t;
    

    listFIRST_LIST_INTEGRITY_CHECK_VALUE和listSECOND_LIST_INTEGRITY_CHECK_VALUE:用来检查列表的完整性,需要将宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES设置为1,默认不开启

    #if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
        #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
    
    
    #else
        #define listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE               TickType_t xListItemIntegrityValue1;
        #define listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE              TickType_t xListItemIntegrityValue2;
    
        #define listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )     ( pxItem )->xListItemIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
        #define listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE( pxItem )    ( pxItem )->xListItemIntegrityValue2 = pdINTEGRITY_CHECK_VALUE

    uxNumberOfItems: 用来记录列表中的列表项的数量

    pxIndex: 用于遍历链表,指向由listGET_OWNER_OF_NEXT_ENTRY()函数返回的列表项

    xListEnd: 指向列表最后一个列表项,变量类型为MiniListItem_t

    1.2 列表项

    FreeRTOS提供了两种列表项:列表项和迷你列表项

    1.2.1 列表项

    struct xLIST_ITEM
    {
        listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
        configLIST_VOLATILE TickType_t xItemValue;          /*< The value being listed.  In most cases this is used to sort the list in descending order. */
        struct xLIST_ITEM * configLIST_VOLATILE pxNext;     /*< Pointer to the next ListItem_t in the list. */
        struct xLIST_ITEM * configLIST_VOLATILE pxPrevious; /*< Pointer to the previous ListItem_t in the list. */
        void * pvOwner;                                     /*< Pointer to the object (normally a TCB) that contains the list item.  There is therefore a two way link between the object containing the list item and the list item itself. */
        void * configLIST_VOLATILE pvContainer;             /*< Pointer to the list in which this list item is placed (if any). */
        listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          /*< Set to a known value if configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES is set to 1. */
    };
    typedef struct xLIST_ITEM ListItem_t;                   /* For some reason lint wants this as two separate definitions. */

    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE 和 listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE: 检查列表项完整性

    xItemValue:列表项值

    pxNext:指向下一个列表项

    pxPrevious:指向前一列表项,与pxNext配合实现类似双向链表功能

    pvOwner:记录此列表项归谁拥有,通常是任务控制块

    pvContainer:用来记录此列表项归哪个列表

    1.2.2 迷你列表项

    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;

    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE:用来检查迷你列表项的完整性

    xItemValue:记录列表列表项值

    pxNext:指向下一个列表项

    pxPrevious:指向前一列表项

    有些情况下不需要列表项这么全的功能,用列表项会浪费内存,所以定义迷你列表项

    2. 相关API函数

    2.1 列表初始化

    函数vListInitialise()完成新创建或定义的列表。列表初始化即初始化列表结构体List_t中各个成员变量。

    void vListInitialise( List_t * const pxList )
    {
        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 );
    }

    pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd ):pxIndex指向每遍历一下最后指向的列表项,当前列表只有一个列表项,是xListEnd,所以pxIndex指向xListEnd

    pxList->xListEnd.xItemValue = portMAX_DELAY :xListEnd的列表项值初始化为portMAX_DELAY,通过相关代码可以看到portMAX_DELAY的值可以为0xffff或0xffffffffUL,在FreeRTOS.h中宏定义的configUSE_16_BIT_TICKS确定portMAX_DELAY的值

    #define configUSE_16_BIT_TICKS                  0 
    #if( configUSE_16_BIT_TICKS == 1 )
        typedef uint16_t TickType_t;
        #define portMAX_DELAY ( TickType_t ) 0xffff
    #else
        typedef uint32_t TickType_t;
        #define portMAX_DELAY ( TickType_t ) 0xffffffffUL

    pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd ):初始化列表项xListEnd的pxNext变量,因为只有一个列表项xListEnd,因此pxNext只能指向自身

    pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd ):初始化列表项xListEnd的pxPrevious变量,因为只有一个列表项xListEnd,因此pxNext只能指向自身

    pxList->uxNumberOfItems = ( UBaseType_t ) 0U:标记列表项个数为0,可以看出不算xListEnd

    listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )和listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList ):初始化列表项里用来检查完整性的变量,根据相关代码可以看到当宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES为1时有效,根据不同MCU配置相应的宏configUSE_16_BIT_TICKS值为0x5a5a(16位MCU)或0x5a5a5a5aUL(32位MCU)

    #if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
        #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )
        #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )
    #else
        #define listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList )  ( pxList )->xListIntegrityValue1 = pdINTEGRITY_CHECK_VALUE
        #define listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList )  ( pxList )->xListIntegrityValue2 = pdINTEGRITY_CHECK_VALUE
    
    #if( configUSE_16_BIT_TICKS == 1 )
        #define pdINTEGRITY_CHECK_VALUE 0x5a5a
    #else
        #define pdINTEGRITY_CHECK_VALUE 0x5a5a5a5aUL

    列表初始化完成后:
    这里写图片描述

    2.2 列表项初始化

    函数vListInitialiseItem()完成列表项初始化

    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,并且给用于完整性检查的变量赋值。

    列表项根据实际使用情况来初始化,所以其初始化函数很短。

    2.3 列表项插入

    通过vListInsert()函数完成列表项插入

    void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
    {
        ListItem_t *pxIterator;
        const TickType_t xValueOfInsertion=pxNewListItem->xItemValue;
        listTEST_LIST_INTEGRITY( pxList );
        listTEST_LIST_ITEM_INTEGRITY( pxNewListItem );
        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;
        pxNewListItem->pxNext->pxPrevious = pxNewListItem;
        pxNewListItem->pxPrevious = pxIterator;
        pxIterator->pxNext = pxNewListItem;
        pxNewListItem->pvContainer = ( void * ) pxList;
        ( pxList->uxNumberOfItems )++;
    }

    参数: pxList:列表项要插入的列表;pxNewListItem:要插入的列表项

    const TickType_t xValueOfInsertion=pxNewListItem->xItemValue:获取要插入列表项值(列表项成员变量xItemValue的值),根据这个值来确定列表项要插入的位置

    listTEST_LIST_INTEGRITY( pxList )和listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ):检查列表和列表项完整性,通过相关源代码可以看出实现检查完整性代码需要实现断言函数configASSERT()

    #if( configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES == 0 )
        #define listTEST_LIST_ITEM_INTEGRITY( pxItem )
        #define listTEST_LIST_INTEGRITY( pxList )
    #else
        #define listTEST_LIST_ITEM_INTEGRITY( pxItem )  configASSERT( ( ( pxItem )->xListItemIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxItem )->xListItemIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
        #define listTEST_LIST_INTEGRITY( pxList )       configASSERT( ( ( pxList )->xListIntegrityValue1 == pdINTEGRITY_CHECK_VALUE ) && ( ( pxList )->xListIntegrityValue2 == pdINTEGRITY_CHECK_VALUE ) )
    
    #define vAssertCalled(char,int) printf("Error:%s,%d\r\n",char,int)
    #define configASSERT(x) if((x)==0) vAssertCalled(__FILE__,__LINE__)

    if( xValueOfInsertion == portMAX_DELAY ):获取列表项插入到什么位置,如果插入列表项的值等于portMAX_DELAY,即列表项值为最大值,此时插入的位置为列表最末尾

    pxIterator = pxList->xListEnd.pxPrevious:获取要插入点,列表中xListEnd表示列表末尾,初始化列表时xListEnd的列表值也是portMAX_DELAY,尽管两个值一样,但是要把插入的列表项放在xListEnd前面

    for( pxIterator = ( ListItem_t * ) &( pxList->xListEnd ); pxIterator->pxNext->xItemValue <= xValueOfInsertion; pxIterator = pxIterator->pxNext ) :如果列表项的值不等于portMAX_DELAY那么就需要在列表中遍历,寻找插入位置,用for循环遍历列表寻找插入点

    插入代码:

    pxNewListItem->pxNext = pxIterator->pxNext;
    pxNewListItem->pxNext->pxPrevious = pxNewListItem;
    pxNewListItem->pxPrevious = pxIterator;
    pxIterator->pxNext = pxNewListItem;

    插入代码用来把要插入的列表项插入到列表当中(找到升序中的比他大的列表项的前一列表项的后面)

    pxNewListItem->pvContainer = ( void * ) pxList:插入后,列表项成员变量pvContainer记录此列表项属于哪个列表

    pxList->uxNumberOfItems:列表成员数量加1

    2.4 列表项末尾插入

    通过vListInsertEnd()函数完成列表项末尾的插入

    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 );
        pxNewListItem->pxNext = pxIndex;
        pxNewListItem->pxPrevious = pxIndex->pxPrevious;
        mtCOVERAGE_TEST_DELAY();
        pxIndex->pxPrevious->pxNext = pxNewListItem;
        pxIndex->pxPrevious = pxNewListItem;
        pxNewListItem->pvContainer = ( void * ) pxList;
        ( pxList->uxNumberOfItems )++;
    }

    参数:pxList:列表项要插入的列表;pxNewListItem:要插入的列表项

    listTEST_LIST_INTEGRITY( pxList )和listTEST_LIST_ITEM_INTEGRITY( pxNewListItem ):先进行列表和列表项的完整性检查

    pxNewListItem->pxNext = pxIndex;
    pxNewListItem->pxPrevious = pxIndex->pxPrevious;
    mtCOVERAGE_TEST_DELAY();
    pxIndex->pxPrevious->pxNext = pxNewListItem;
    pxIndex->pxPrevious = pxNewListItem;

    将要插入的列表项插入到列表末尾,列表末尾指的是pxIndex所指向的列表项的前面(列表中pxIndex成员变量用来遍历列表,pxIndex所指向的列表项就是要遍历的开始列表项)

    pxNewListItem->pvContainer = ( void * ) pxList:标记新列表项pxNewListItem属于列表pxList

    ( pxList->uxNumberOfItems )++:列表中的列表项数目加一

    2.5 列表项的删除

    通过uxListRemove()函数完成列表项插入

    UBaseType_t uxListRemove( ListItem_t * const pxItemToRemove )
    {
        List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer;
        pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious;
        pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext;
        mtCOVERAGE_TEST_DELAY();
        if( pxList->pxIndex == pxItemToRemove )
        {
            pxList->pxIndex = pxItemToRemove->pxPrevious;
        }
        else
        {
            mtCOVERAGE_TEST_MARKER();
        }
        pxItemToRemove->pvContainer = NULL;
        ( pxList->uxNumberOfItems )--;
        return pxList->uxNumberOfItems;
    }

    参数:pxItemToRemove:要删除的列表项

    List_t * const pxList = ( List_t * ) pxItemToRemove->pvContainer:读出要删除列表项的成员变量pvContainer得到此列表项处于哪个列表

    pxItemToRemove->pxNext->pxPrevious = pxItemToRemove->pxPrevious 和 pxItemToRemove->pxPrevious->pxNext = pxItemToRemove->pxNext:将要删除列表项的前后列表项”连接”起来

    if( pxList->pxIndex == pxItemToRemove ){pxList->pxIndex = pxItemToRemove->pxPrevious;}:如果列表的pxIndex正好指向要删除的列表项,则pxIndex指向被删除列表项前一列表项

    pxItemToRemove->pvContainer = NULL:删除的成员变量pvContainer清零

    ( pxList->uxNumberOfItems )–:列表中列表项数目减一

    2.6 列表的遍历

    列表的遍历使用listGET_OWNER_OF_NEXT_ENTRY()函数,本质上是一个宏

    #define listGET_OWNER_OF_NEXT_ENTRY( pxTCB, pxList )                                        
    {                                       
        List_t * const pxConstList = ( pxList );
        ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                            
        if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList )->xListEnd ) )  
        {                                           
            ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext;                        
        }                                           
        ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner;                                          
    }

    参数:pxTCB:保存pxIndex所指向的列表项的pvOwner变量值,通常是一个任务的任务控制块;pxList:表示要遍历的列表

    ( pxConstList )->pxIndex = ( pxConstList )->pxIndex->pxNext:列表的pxIndex变量指向下一个列表项

    if( ( void * ) ( pxConstList )->pxIndex == ( void * ) &( ( pxConstList)->xListEnd){(pxConstList)->pxIndex = (pxConstList)->pxIndex->pxNext;}:如果成员变量pxIndex指向了列表的xListEnd成员变量,则跳过xListEnd,重新指向处于列表头的列表项即完成了对列表的遍历

    ( pxTCB ) = ( pxConstList )->pxIndex->pvOwner:将pxIndex所指向新列表项的pvOwner赋值给pxTCB

    展开全文
  • 1. 列表和列表项

    2019-05-24 21:18:44
    列表和列表项 列表是FreeRTOS中的一个数据结构,类似于链表,挂载各种数据 FreeRTOS中的列表为双向链表,有previous和next指针,用于遍历列表项。 typedef struct xLIST { listFIRST_LIST_INTEGRITY_CHECK_VALUE ...

    列表和列表项

    列表

    列表是一个数据结构,用来追踪任务,列表中有一个指针指向列表项

    列表是一个结构体,内部携带一个指针,指针指向列表项,列表项形成双向链式结构挂载在列表下

    一个列表下面可以有很多的列表项,每个列表项都会有一个指针指向这个列表,下面是一个列表

    typedef struct xLIST
    {
    	listFIRST_LIST_INTEGRITY_CHECK_VALUE
    	configLIST_VOLATILE UBaseType_t uxNumberOfItems;	// 记录列表挂载列表项数量
    	ListItem_t * configLIST_VOLATILE pxIndex;			// 指向列表项的指针,用于遍历列表
    	MiniListItem_t xListEnd;							// 不会改变,永远指向首/尾列表项,xListEnd
    	listSECOND_LIST_INTEGRITY_CHECK_VALUE
    } List_t;
    

    listFIRST_LIST_INTEGRITY_CHECK_VALUE与listSECOND_LIST_INTEGRITY_CHECK_VALUE用于检测列表的完整性,使能后自动添加变量

    uxNumberOfItems:记录列表中列表项的数量

    pxIndex:记录当前某个列表项的地址,用于遍历列表(指针,记录当前列表项位置,列表项按照升序排列,寻址访问对应列表项)

    xListEnd:列表中的最后一个列表项,用来表示列表结束,是一个阉割版的列表项,迷你列表项(不要不必要的东西)

    列表初始化
    void vListInitialise( List_t * const pxList )
    {
    	pxList->pxIndex = ( ListItem_t * ) &( pxList->xListEnd );				// 初始化索引地址,默认挂载 xListEnd
    	pxList->xListEnd.xItemValue = portMAX_DELAY;							// 辅助值 排序节点,xListEnd为最后一节点
    	pxList->xListEnd.pxNext = ( ListItem_t * ) &( pxList->xListEnd );		// 当前列表为空,只挂载 xListEnd
    	pxList->xListEnd.pxPrevious = ( ListItem_t * ) &( pxList->xListEnd );	// 再挂载是通过 xListEnd
    	pxList->uxNumberOfItems = ( UBaseType_t ) 0U;							// 当前挂载列表项数量为0,链表节点计数器
    	listSET_LIST_INTEGRITY_CHECK_1_VALUE( pxList );							// 宏,变量定义
    	listSET_LIST_INTEGRITY_CHECK_2_VALUE( pxList );
    }
    

    初始化列表,由于列表项的数量为0,所以大多数据被初始化为0,各种指针指向xListEnd,也就是列表中的迷你列表项,也是双向列表的首尾

    列表项

    struct xLIST_ITEM
    {
    	listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE			// 宏值,列表项完整性考虑
    	configLIST_VOLATILE TickType_t xItemValue;			// 列表项辅助值,进行排序
    	struct xLIST_ITEM * configLIST_VOLATILE pxNext;		// 列表项 next 指针
    	struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;	// 列表项 prev 指针
    	void * pvOwner;										// 列表项归属TCB
    	void * configLIST_VOLATILE pvContainer;				// 列表项归属列表
    	listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE
    };
    typedef struct xLIST_ITEM ListItem_t;
    

    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE与listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE用于检测列表项的完整性

    xItemValue:当前列表项挂载的位置,记录列表项在链表中的位置(xListEnd是0)

    pxNext:指向下一个列表项

    pxPrevious:指向上一个列表项(实现双向链表)

    pvOwner:记录列表项的拥有者(归属TCB)

    pvContainer:记录列表项归属列表(就绪,阻塞列表)

    迷你列表项

    列表项的阉割版(主要是节省资源),作为列表下挂列表项的头和尾

    struct xMINI_LIST_ITEM		// 一般是xEndList
    {
       listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE
       configLIST_VOLATILE TickType_t xItemValue;			// 列表项挂载值,列表项排序
       struct xLIST_ITEM * configLIST_VOLATILE pxNext;		// 列表项 next 指针
       struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;	// 列表项 prev 指针
    };
    typedef struct xMINI_LIST_ITEM MiniListItem_t;
    

    listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE用于检测迷你列表项的完整

    xItemValue:用于记录列表项值

    pxNext:指向下一个列表项

    pxPrevious:指向上一个列表项

    列表项初始化
    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 );
    }
    

    列表项插入

    末尾插入

    找到列表项最后一项,也就是xListEnd的previous指针指向列表项

    步骤:

    1、移动列表项指针,找到列表最终列表项的项值(xListEnd是首也是尾,最后一个列表项就是(xListEnd - 1))

    2、改变新插入列表项的指针,previous指向(xListEnd - 1)与next指向(xListEnd )

    3、改变(xListEnd - 1)的next指针

    4、改变(xListEnd)的previous指针(xListEnd->privious 指向新插入的列表项)

    5、标记列表项归属

    6、列表的列表项数量自增(列表项的项值也要改变)

    void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )// 指定列表项要插入哪个列表,以及要插入的列表项
    {
    	ListItem_t * const pxIndex = pxList->pxIndex;	// 列表项索引,获取当前索引,
    	pxNewListItem->pxNext = pxIndex;				// 新插入列表项 加入链表, pxNewListItem->pxNext 指向 xEnd
    	pxNewListItem->pxPrevious = pxIndex->pxPrevious;// 新插入列表项 加入链表, pxNewListItem->pxPrev 指向 xEnd->pre 
    	pxIndex->pxPrevious->pxNext = pxNewListItem;	// 改变 (xEnd - 1)的 next 指针,
    	pxIndex->pxPrevious = pxNewListItem;			// 改变 xEnd 的 previous 指针
    	pxNewListItem->pvContainer = ( void *) pxList;	// 新插入列表项的归属列表
    	( pxList->uxNumberOfItems )++;					// 列表项数目自增
    }
    

    相当于是在 xListEnd 前面插入一个新的列表项(改变 xListEnd的pre指针)

    一共需要改变四个指针,新插入的列表项的per和next指针,之(xListEnd - 1)的next指针,xListEnd的pre指针

    pxIndex 值是第0个列表项,也是最后一个列表项(双向列表) xListEnd,通过next指针遍历链表

    升序插入

    通过列表项项值xItemValue比对,查找插入位置

    步骤:

    1、通过要插入的列表项的项值,找到要插入列表项的前一个列表项( 项值 - 1)

    2、改变(项值 - 1)的next指针,新插入列表项的previous指针,新插入列表项的next指针

    3、改变(项值 + 1)的previous指针

    4、标记新插入列表项归属列表

    5、列表的列表项数量自增

    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;	// 索引值在链表最后,直接挂载在 End后,改变 xListEnd.pxPrevious
    	}
    	else
    	{
    		for (	pxIterator = ( ListItem_t * ) &( pxList->xListEnd );// 索引从链表最后开始往前索引
    				pxIterator->pxNext->xItemValue <= xValueOfInsertion;// 通过next索引,与要插入列表项值比较
    				pxIterator = pxIterator->pxNext )					// 移动next指针进行索引
    		{
    			// xValueOfInsertion > pxIterator->pxNext->xItemValue,即pxIterator为要插入列表项位置前一个
    		}
    	}
    	pxNewListItem->pxNext = pxIterator->pxNext;			// 改变要插入列表项的 next 指针
    	pxNewListItem->pxNext->pxPrevious = pxNewListItem;	// 改变要插入列表项的 prev 指针
    	pxNewListItem->pxPrevious = pxIterator;				// 
    	pxIterator->pxNext = pxNewListItem;
    
    	pxNewListItem->pvContainer = ( void * ) pxList;		// 通过pvContainer标记列表项属于哪个列表
    	( pxList->uxNumberOfItems )++;						// 列表的列表项数目自增
    }
    

    删除

    步骤:

    1、设置要删除列表项(项值 - 1)的next指针

    2、设置要删除列表项(项值 + 1)的previous指针

    3、清空要删除列表项的previous与next指针

    4、清除列表项归属列表标记

    5、列表项数量自减

    void vListDelete( List_t * const pxList, ListItem_t * const pxNewListItem )
    {
       ListItem_t presentListItem;				// 使用临时列表项遍历列表项
       presentListItem = pxList->pxIndex;		// 获取当前列表项,此时为xListEnd
    
       if( pxNewListItem->xItemValue == portMAX_DELAY)	// 当前索引位置为链表最后位置
       {
       	  presentListItem->xItemValue = pxList->pxIndex;	// 直接插入最后
       }
       else
       {
       	for( presentListItem->xItemValue = pxList->pxIndex;				/* 从起始列表项开始*/
       		 presentListItem->xItemValue = pxNewListItem->xItemValue;	/* 当列表项匹配就结束*/
       		  presentListItem = presentListItem->next);					/* 移动next指针*/
       }
       presentListItem->pxPrevious->pxNext = pxList->pxIndex;				// 要删除节点 前一个的next指针
       presentListItem->pxNext->pxPrevious = presentListItem->pxPrevious;	// 要删除节点 下一个的prev指针
       presentListItem->pxNext = NULL;										// 要删除节点自己的指针
       presentListItem->pxPrevious = NULL;
    
       presentListItem->pvContainer = NULL;
       pxList->xItemValue--;
    }
    

    任务的执行由系统来调度,为了调度任务每个任务都会定义一个任务控制块,这个任务控制块相当于任务的身份证,保存有任务的所有信息

    系统堆任务的全部操作都是通过任务控制块来实现的

    任务块中的列表项,都标记有归属列表,通过列表可以遍历所有的列表项

    展开全文
  • 将FreeRTOS中列表和列表项跟C语言中双向链表进行对比分析,介绍了列表和列表项的原理。另外,总结了列表和列表项的所有函数和宏定义,并对所有函数的源码进行剖析注释。
  • 去除列表项符号

    千次阅读 2019-12-26 17:16:17
    去除列表项符号 在CSS中,我们也是使用list-style-type属性来去除有序列表或无序列表的列表项符号的。 语法 list-style-type:none 说明 由于列表样式比较丑,因此在实际开发中,大多数情况下我们都需要使用...
  • FreeRTOS 列表和列表项FreeRTOS 列表和列表项初始化列表初始化列表项列表项插入到列表中,列表项所在的位置取决于列表项列表项值(xItemValue)。将列表项插入到列表末端 FreeRTOS 列表和列表项 FreeRTOS内核...
  • 列表和列表项是FreeRTOS的一个数据结构,是FreeRTOS的基石。1.列表 列表是FreeRTOS中的一个数据结构,和链表类似,它的定义位于文件list.c和list.h中。 列表的结构体定义如下:typedef struct xLIST { listFIRST_...
  • 要想看懂FreeRTOS 源码并学习其原理,有一个东西绝对跑不了,那就是FreeRTOS 的列表和列表项。列表和列表项是FreeRTOS 的一个数据结构,FreeRTOS 大量使用到了列表和列表项,它是FreeRTOS 的基石。要想深入学习并...
  • CSS 列表 从某种意义上讲,不是描述性的文本的任何内容都可以认为是列表。人口普查、太阳系、家谱、参观菜单,甚至你的所有朋友都可以表示为一个列表或者是列表...例如,在一个无序列表中,列表项的标志 (marker) ...
  • 原GRUB列表项如下: 可以看到有很多根本没有用的选项,现在要做的是删除这些无用列表项,即自定义配置列表项,即配置grub.cfg文件 步骤: 进入/boot目录下,查看grub是grub1(grub)还是grub2,选择最高的进行修改...
  • SharePoint REST API - 列表和列表项

    千次阅读 2017-08-23 10:24:31
    博客地址:http://blog.csdn.net/FoxDave 本篇主要讲述如何用SharePoint REST操作列表和列表项。阅读本篇时请先了解前面讲述的REST介绍和基本操作。
  • 列表与列表项简介 列表和列表项是FreeRTOS中的一个数据结构,FreeRTOS中使用了大量的列表和列表项,是FreeRTOS的基石。 列表 列表在概念上和链表有点类似,列表被用来跟踪FreeRTOS中的任务。与列表相关...
  • 内容比较多,没贴完,但关键的地方都在上面,点击列表项能够把loadtext显示出来,但是上下滑动之后,显示的就不是我刚刚点击的那个列表项的TextView,而是其他列表项的Textview,应该是不能在这里用ViewHolder,...
  • 列表作用:用于追踪freeRTOS的任务 列表: 定义方法:List_t ****; 列表的成员变量:(不包括列表的完整性检测) uxNumbersOfItems //用于记录列表项的数量 ...列表项成员变量:(不包括列表项完整性...
  • 用三种方法实现了点击列表项,输出列表项中的内容。 现有如下列表: 1 <ul id="myLinks"> 2 <li id="go">Go somewhere</li> 3 <li id="do">Do something</li> 4 <li id=...
  • Qml列表项拖放

    2017-11-25 15:10:47
    ListModel的move(int from, int to, int n) 可以将列表项进行移动 根据鼠标的拖动位置, 可以判断出需要移动项的序号 var lastIndex = listview.indexAt(mousearea.mouseX + listItem.x,
  • QComboBox 隐藏列表项

    千次阅读 2019-06-13 17:38:19
    比如一个QComboBox有四个列表项,分别是 1 2 3 4 现在需要把3隐藏,需要的时候再显示出来。 方法1: 先删掉3,需要的时候再插入,这样可能导致index变化,有时候不是很实用。 方法2: QListView* ...
  • CSS 列表 从某种意义上讲,不是描述性的文本的任何内容都可以认为是列表。人口普查、太阳系、家谱、参观菜单,甚至你的所有朋友都可以表示为一个列表或者是列表的列表。...例如,在一个无序列表中,列表项的标志
  • ListView显示不同类型的列表项的例子

    千次下载 热门讨论 2013-01-23 08:28:30
    在同一个ListView显示不同类型的列表项
  • 标签设置,其中每一个列表项使用 <li>...</li> 标签设置。 具体实例如下:???????????? <!DOCTYPE html> <html lang="en"> <head> <meta charset="utf-8"> <title...
  • 但是,我们项目中仅仅展示数据是不够的,我们经常还有列表项的单击事件、添加列表项、删除列表项等。今天我们就着重讲解一下RecyclerView列表项的单击事件、添加列表项、删除列表项。 效果: 1.Recy...
  •  在FreeRTOS中,列表与列表项使用得非常多,是FreeRTOS的一个数据结构,学习过数据结构的同学都知道,数据结构能使我们处理数据更加方便快速,能快速找到数据,在FreeRTOS中,这种列表与列表项更是必不可少的,能让...
  • 金蝶UI operamasks-UI 下拉列表 获取选中列表项的文本 text方法 它的实现方式其实是在你定义的存储值的 input 后面紧跟着一个 input 用于显示 选项 option 的 text 值,所以通过以下方法就可以获取到: $("#...
  • Vue实现table列表项上下移动

    千次阅读 2019-01-22 17:36:56
    el-tabel 列表项实现上移,下移,删除功能 结合Element组件,scope中有三个参数(row,cow,$index)分别表示行内容、列内容、以及此行索引值, table上绑定数组 :data=“newsList”。 上移和下调两个按钮,并绑定...
  • 在使用win32 combox 时发现只能添加一个列表项,不知道什么原因, 代码如下: HWND hWndComboBox = GetDlgItem(hwndDlg, CBCOM); SendMessage(hWndComboBox, CB_ADDSTRING, 0, (LPARAM)TEXT("COM1")); ...
  • ListView控件可以通过控件对应数据存储删除列表项,具体使用: 数据存储.removeRow(元素索引位置) 删除指定位置的一个列表项。 数据存储如果不知道程序定义的数据存储名,可以通过model()函数获取对应ListView控件...
  • 2、插入三个ICON作为列表项的图标显示,ID分别为:IDI_ICON1、IDI_ICON2、IDI_ICON3。插入两个Bitmap作为列表头图标的显示图标,ID分别为:IDB_BITMAP1、IDB_BITMAP2。 3、基本步骤都是:1、Create创建图像列表; 2...
  • 需求描述 ...列表页dom挂载完成后,判断路由是否有hash,若有页面定位到对应hash的列表项。 <template> <div> <ul> <li v-for="item in list" :key="item.id" :id=...
  • 如题,在OnInitDialog()函数中,使用InsertItem()函数插入新的列表项后运行程序,没有显示出列表项的名称,把控件属性里的"Owner Data"改为false就行了。

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 36,896
精华内容 14,758
关键字:

列表项