溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

FreeRTOS列表和列表項(xiàng)怎么應(yīng)用

發(fā)布時(shí)間:2022-04-08 15:20:00 來源:億速云 閱讀:239 作者:iii 欄目:開發(fā)技術(shù)

今天小編給大家分享一下FreeRTOS列表和列表項(xiàng)怎么應(yīng)用的相關(guān)知識(shí)點(diǎn),內(nèi)容詳細(xì),邏輯清晰,相信大部分人都還太了解這方面的知識(shí),所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

前言

FreeRTOS內(nèi)核調(diào)度大量使用了列表(list)和列表項(xiàng)(list item)數(shù)據(jù)結(jié)構(gòu)。我們?nèi)绻胍惶紽reeRTOS背后的運(yùn)行機(jī)制,首先遇到的攔路虎就是列表和列表項(xiàng)。對(duì)于FreeRTOS內(nèi)核來說,列表就是它最基礎(chǔ)的部分。

列表被FreeRTOS調(diào)度器使用,用于跟蹤任務(wù),處于就緒、掛起、延時(shí)的任務(wù),都會(huì)被掛接到各自的列表中。用戶程序如果有需要,也可以使用列表。

FreeRTOS列表使用指針指向列表項(xiàng)。一個(gè)列表(list)下面可能有很多個(gè)列表項(xiàng)(list item),每個(gè)列表項(xiàng)都有一個(gè)指針指向列表。如圖1-1所示。

FreeRTOS列表和列表項(xiàng)怎么應(yīng)用

圖1-1:列表與列表項(xiàng)

列表項(xiàng)有兩種形式,全功能版的列表項(xiàng)xLIST_ITEM和迷你版的列表項(xiàng)xMINI_LIST_ITEM。我們來看一下它們具體的定義,先看全功能版。

struct xLIST_ITEM
{
     listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*用于檢測(cè)列表項(xiàng)數(shù)據(jù)是否完整*/
     configLIST_VOLATILE TickType_t xItemValue;           /*列表項(xiàng)值*/
     struct xLIST_ITEM * configLIST_VOLATILE pxNext;      /*指向列表中下一個(gè)列表項(xiàng)*/
     struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;  /*指向列表中上一個(gè)列表項(xiàng)*/
     void * pvOwner;                                     /*指向一個(gè)任務(wù)TCB*/
     void * configLIST_VOLATILE pvContainer;             /*指向包含該列表項(xiàng)的列表 */
     listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE          /*用于檢測(cè)列表項(xiàng)數(shù)據(jù)是否完整*/
};
typedef struct xLIST_ITEM ListItem_t;

宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE用于檢查列表項(xiàng)數(shù)據(jù)是否完整,在projdefs.h中,如果將宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES設(shè)置為1,則使能列表項(xiàng)數(shù)據(jù)完整性檢查,則宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE會(huì)被兩個(gè)已知的數(shù)值代替。

xItemValue是列表項(xiàng)值,通常是一個(gè)被跟蹤的任務(wù)優(yōu)先級(jí)或是一個(gè)調(diào)度事件的計(jì)數(shù)器值。如果任務(wù)因?yàn)榈却龔年?duì)列取數(shù)據(jù)而進(jìn)入阻塞狀態(tài),則任務(wù)的事件列表項(xiàng)的列表項(xiàng)值保存任務(wù)優(yōu)先級(jí)有關(guān)信息,狀態(tài)列表項(xiàng)的列表項(xiàng)值保存阻塞時(shí)間有關(guān)的信息。這個(gè)變量被configLIST_VOLATILE修飾,configLIST_VOLATILE被映射成C語言關(guān)鍵字volatile,表明這個(gè)變量是“易變的”,告訴編譯器不得對(duì)這個(gè)變量進(jìn)行代碼優(yōu)化,因?yàn)榱斜眄?xiàng)的成員可能會(huì)在中斷服務(wù)程序中被更新。

pxNext和pxPrevious是列表項(xiàng)類型指針,用來指向列表中下一個(gè)和上一個(gè)列表項(xiàng),通過這兩個(gè)指針,列表項(xiàng)之間可以形成類似雙向鏈表結(jié)構(gòu)。

指針pvOwner通常指向一個(gè)任務(wù)TCB。

指針pvContainer指向包含該列表項(xiàng)的列表。

迷你版的列表項(xiàng)xMINI_LIST_ITEM是全功能版列表項(xiàng)xLIST_ITEM的一個(gè)子集,定義如下所示:

struct xMINI_LIST_ITEM
{
     listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE           /*用于檢測(cè)列表項(xiàng)數(shù)據(jù)是否完整*/
     configLIST_VOLATILE TickType_t xItemValue;
     struct xLIST_ITEM * configLIST_VOLATILE pxNext;
     struct xLIST_ITEM * configLIST_VOLATILE pxPrevious;
typedef struct xMINI_LIST_ITEM MiniListItem_t;

既然有了全功能版的列表項(xiàng),為什么還要聲明迷你版的列表項(xiàng)呢?這是因?yàn)榱斜斫Y(jié)構(gòu)體需要一個(gè)列表項(xiàng)成員,但又不需要列表項(xiàng)中的所有字段,所以才有了迷你版列表項(xiàng)。列表結(jié)構(gòu)體定義為:

typedef struct xLIST
{
     listFIRST_LIST_INTEGRITY_CHECK_VALUE                        /*用于檢測(cè)列表項(xiàng)數(shù)據(jù)是否完整*/
     configLIST_VOLATILE UBaseType_t uxNumberOfItems;
     ListItem_t * configLIST_VOLATILE pxIndex;                   /*用于遍歷列表*/
     MiniListItem_t xListEnd;                                    /*列表項(xiàng)*/
     listSECOND_LIST_INTEGRITY_CHECK_VALUE                       /*用于檢測(cè)列表項(xiàng)數(shù)據(jù)是否完整*/
}List_t;

和列表項(xiàng)定義相同,宏listFIRST_LIST_INTEGRITY_CHECK_VALUE和listSECOND_LIST_INTEGRITY_CHECK_VALUE用于檢查列表項(xiàng)數(shù)據(jù)是否完整,在projdefs.h中,如果將宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES設(shè)置為1,則使能列表項(xiàng)數(shù)據(jù)完整性檢查,則宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE會(huì)被兩個(gè)已知的數(shù)值代替。

uxNumberOfItems表示該列表中掛接的列表項(xiàng)數(shù)目,0表示列表為空。

列表項(xiàng)類型指針用于遍歷列表,列表初始化后,這個(gè)指針指向&xListEnd。通過宏listGET_OWNER_OF_NEXT_ENTRY()來獲取列表中的下一個(gè)列表項(xiàng)。

列表項(xiàng)xListEnd用于標(biāo)記列表結(jié)束。xListEnd.xItemValue被初始化為一個(gè)常數(shù),其值與硬件架構(gòu)相關(guān),為0xFFFF(16位架構(gòu))或者0xFFFFFFFF(32位架構(gòu))。

下面我們看一下列表操作。FreeROTS提供了幾個(gè)API函數(shù),用于初始化列表和列表項(xiàng)以及列表項(xiàng)插入操作。

1.初始化列表

列表結(jié)構(gòu)體中包含一個(gè)列表項(xiàng)成員,主要用于標(biāo)記列表結(jié)束。初始化列表就是把這個(gè)列表項(xiàng)插入到列表中。

void vListInitialise( List_t * const pxList )
{
     /*列表索引指向列表項(xiàng)*/
     pxList->pxIndex = ( ListItem_t * )&( pxList->xListEnd );                  
     /* 設(shè)置為最大可能值 */
     pxList->xListEnd.xItemValue =portMAX_DELAY;
     /* 列表項(xiàng)xListEnd的pxNext和pxPrevious指針指向了它自己 */
     pxList->xListEnd.pxNext = (ListItem_t * ) &( pxList->xListEnd );
     pxList->xListEnd.pxPrevious= ( ListItem_t * ) &( pxList->xListEnd );
     pxList->uxNumberOfItems = ( UBaseType_t) 0U;
      /* 設(shè)置為已知值,用于檢測(cè)列表數(shù)據(jù)是否完整*/
     listSET_LIST_INTEGRITY_CHECK_1_VALUE(pxList );
     listSET_LIST_INTEGRITY_CHECK_2_VALUE(pxList );
}

如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES設(shè)置為1,則使能列表項(xiàng)數(shù)據(jù)完整性檢查,則宏listSET_LIST_INTEGRITY_CHECK_1_VALUE()和listSET_LIST_INTEGRITY_CHECK_2_VALUE被一個(gè)已知值代替,默認(rèn)為0x5a5a(16位架構(gòu))或者0x5a5a5a5a(32位架構(gòu))。

假設(shè)禁止列表數(shù)據(jù)完整性檢查,初始化后的列表如圖1-2所示,uxNumberOfItems被初始化為0,xListEnd.xItemValue初始化為0xffffffff,pxIndex、xListEnd.pxNext和xListEnd.pxPrevious初始化為指向列表項(xiàng)xListEnd。

FreeRTOS列表和列表項(xiàng)怎么應(yīng)用

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

2.初始化列表項(xiàng)

列表項(xiàng)的初始比較簡(jiǎn)單,只要確保列表項(xiàng)不在任何列表中即可。

void vListInitialiseItem( ListItem_t * const pxItem )
{
     pxItem->pvContainer = NULL;
     /*設(shè)置為已知值,用于檢測(cè)列表項(xiàng)數(shù)據(jù)是否完整*/
     listSET_FIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );
     listSET_SECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE(pxItem );
}

如果宏configUSE_LIST_DATA_INTEGRITY_CHECK_BYTES設(shè)置為1,則使能列表項(xiàng)數(shù)據(jù)完整性檢查,則宏listFIRST_LIST_ITEM_INTEGRITY_CHECK_VALUE和listSECOND_LIST_ITEM_INTEGRITY_CHECK_VALUE會(huì)被兩個(gè)已知的數(shù)值代替,默認(rèn)為0x5a5a(16位架構(gòu))或者0x5a5a5a5a(32位架構(gòu))。

假設(shè)禁止列表項(xiàng)數(shù)據(jù)完整性檢查,初始化后的列表項(xiàng)如圖1-3所示。僅是將指針pvContainer設(shè)置為空指針,該指針用于指向包含該列表項(xiàng)的列表,這里設(shè)置為NULL表示這個(gè)列表項(xiàng)不屬于任何列表。

FreeRTOS列表和列表項(xiàng)怎么應(yīng)用

圖1-3:初始化后的列表項(xiàng)

3.將列表項(xiàng)插入到列表中,列表項(xiàng)所在的位置取決于列表項(xiàng)的列表項(xiàng)值(xItemValue)。

每個(gè)列表項(xiàng)對(duì)象都有一個(gè)列表項(xiàng)值(xItemValue),通常是一個(gè)被跟蹤的任務(wù)優(yōu)先級(jí)或是一個(gè)調(diào)度事件的計(jì)數(shù)器值。調(diào)用API函數(shù)vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem)可以將pxNewListItem指向的列表項(xiàng)插入到pxList指向的列表中,列表項(xiàng)在列表的位置由pxNewListItem->xItemValue決定,按照升序排列。

void vListInsert( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t *pxIterator;
const TickType_t xValueOfInsertion = pxNewListItem->xItemValue;
         /* 檢查列表和列表項(xiàng)數(shù)據(jù)的完整性,僅當(dāng)configASSERT()定義時(shí)有效。*/
         listTEST_LIST_INTEGRITY( pxList );
         listTEST_LIST_ITEM_INTEGRITY(pxNewListItem );
         /*將新的列表項(xiàng)插入到列表,根據(jù)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 )++;
}

根據(jù)xItemValue的值將新的列表項(xiàng)插入到列表。如果列表中存在與新列表項(xiàng)xItemValue值相同的列表項(xiàng),則新插入的列表項(xiàng)位于它之后。如果列表項(xiàng)的xItemValue值等于portMAX_DELAY(列表結(jié)束標(biāo)記,我們?cè)谥v列表數(shù)據(jù)結(jié)構(gòu)時(shí),說到每個(gè)列表數(shù)據(jù)結(jié)構(gòu)體中都有一個(gè)列表項(xiàng)成員xListEnd,用于標(biāo)記列表結(jié)束。xListEnd.xItemValue被初始化為一個(gè)常數(shù),其值與硬件架構(gòu)相關(guān),為0xFFFF或者0xFFFFFFFF。這個(gè)常數(shù)在移植層定義,即宏portMAX_DELAY),則表示到達(dá)了列表結(jié)束位置。

我們用圖示的方法來講解這個(gè)函數(shù),我們假設(shè)一個(gè)列表項(xiàng)值(xItemValue)為32的列表項(xiàng)插入到如圖1-2所示的初始化后的列表中,調(diào)用vListInsert()函數(shù)后,列表和列表項(xiàng)的關(guān)系如圖1-4所示。列表項(xiàng)xListItem_1的成員指針pxNext和pxPrevious都指向了xListEnd,而xListEnd的成員指針pxNext和pxPrevious都指向了列表項(xiàng)xListItem_1;列表項(xiàng)xListItem_1的成員指針pvContainer指向了列表xList_1;列表成員uxNumberOfItems為1。

FreeRTOS列表和列表項(xiàng)怎么應(yīng)用

圖1-4:將列表項(xiàng)插入到列表

在此基礎(chǔ)上,如果再將一個(gè)列表項(xiàng)值(xItemValue)為40的列表項(xiàng)插入到列表中,調(diào)用vListInsert()函數(shù)后,列表和列表項(xiàng)的關(guān)系如圖1-5所示。

FreeRTOS列表和列表項(xiàng)怎么應(yīng)用

圖1-5:將列表項(xiàng)插入到列表

4.將列表項(xiàng)插入到列表末端

第3節(jié)講的API插入函數(shù)是根據(jù)列表項(xiàng)中的列表項(xiàng)值(xItemValue)來決定插入位置的,本節(jié)所講的API函數(shù)vListInsertEnd()是簡(jiǎn)單的將列表項(xiàng)插入到列表的末端。在下一章任務(wù)創(chuàng)建分析的文章中,將會(huì)遇到這個(gè)API函數(shù),到時(shí)再以圖標(biāo)的形式分析這個(gè)函數(shù),現(xiàn)在給出這個(gè)函數(shù)的源碼。

void vListInsertEnd( List_t * const pxList, ListItem_t * const pxNewListItem )
{
ListItem_t* const pxIndex = pxList->pxIndex;
         /*檢查列表和列表項(xiàng)數(shù)據(jù)的完整性,僅當(dāng)configASSERT()定義時(shí)有效。*/
         listTEST_LIST_INTEGRITY( pxList );
         listTEST_LIST_ITEM_INTEGRITY(pxNewListItem );
         /*向列表中插入新的列表項(xiàng)*/
         pxNewListItem->pxNext = pxIndex;
         pxNewListItem->pxPrevious =pxIndex->pxPrevious;
         mtCOVERAGE_TEST_DELAY();
         pxIndex->pxPrevious->pxNext =pxNewListItem;
         pxIndex->pxPrevious = pxNewListItem;
         pxNewListItem->pvContainer = ( void* ) pxList;
         ( pxList->uxNumberOfItems )++;
}

以上就是“FreeRTOS列表和列表項(xiàng)怎么應(yīng)用”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會(huì)為大家更新不同的知識(shí),如果還想學(xué)習(xí)更多的知識(shí),請(qǐng)關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI