亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

FreeRTOS進(jìn)階之任務(wù)通知示例完全解析

 更新時(shí)間:2022年04月08日 18:48:40   作者:zhzht19861011  
這篇文章主要為大家介紹了FreeRTOS進(jìn)階系列之任務(wù)通知的示例分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪

前言

在FreeRTOS版本V8.2.0中推出了全新的功能:任務(wù)通知。在大多數(shù)情況下,任務(wù)通知可以替代二進(jìn)制信號(hào)量、計(jì)數(shù)信號(hào)量、事件組,可以替代長度為1的隊(duì)列(可以保存一個(gè)32位整數(shù)或指針值),并且任務(wù)通知速度更快、使用的RAM更少!我在FreeRTOS任務(wù)通知一文中介紹了任務(wù)通知如何使用以及局限性,今天我們將分析任務(wù)通知的實(shí)現(xiàn)源碼,看一下任務(wù)通知是如何做到效率與RAM消耗雙贏的。

FreeRTOS信號(hào)量分析一文中我們已經(jīng)知道,F(xiàn)reeRTOS的信號(hào)量是使用隊(duì)列機(jī)制實(shí)現(xiàn)的,數(shù)據(jù)結(jié)構(gòu)也完全是隊(duì)列的那一套。而任務(wù)通知?jiǎng)t不同,它的數(shù)據(jù)結(jié)構(gòu)嵌在任務(wù)TCB(任務(wù)控制塊,見FreeRTOS進(jìn)階之任務(wù)創(chuàng)建中的,并且數(shù)據(jù)結(jié)構(gòu)十分簡單,涉及到任務(wù)TCB的兩個(gè)字段,我們將它單獨(dú)列出來:

volatile uint32_t ulNotifiedValue; 	/*任務(wù)通知值*/  
volatile uint8_t ucNotifyState;	/*任務(wù)通知狀態(tài),標(biāo)識(shí)任務(wù)是否在等待通知等*/

這兩個(gè)字段占用5字節(jié)RAM(本文都是在32位系統(tǒng)下討論),而一個(gè)隊(duì)列數(shù)據(jù)結(jié)構(gòu)至少占用76字節(jié)RAM!這不是同一數(shù)量級(jí)的,所以任務(wù)通知在RAM消耗上完勝。
在分析隊(duì)列和信號(hào)量的文章中,我們知道在使用隊(duì)列、信號(hào)量前,必須先創(chuàng)建隊(duì)列和信號(hào)量,目的是為了創(chuàng)建隊(duì)列數(shù)據(jù)結(jié)構(gòu)。比如使用API函數(shù)xQueueCreate()創(chuàng)建隊(duì)列,用API函數(shù)xSemaphoreCreateBinary()創(chuàng)建二進(jìn)制信號(hào)量等等。再來看任務(wù)通知,由于任務(wù)通知的數(shù)據(jù)結(jié)構(gòu)包含在任務(wù)TCB中,只要任務(wù)存在,任務(wù)通知數(shù)據(jù)結(jié)構(gòu)就已經(jīng)創(chuàng)建完畢,可以直接使用!在易用性上,任務(wù)通知再次獲勝。

要想了解任務(wù)通知在性能上占優(yōu)的原因,就要分析源代碼了。

只有任務(wù)可以等待通知,中斷服務(wù)函數(shù)中不可以。如果等待的通知無效,任務(wù)會(huì)進(jìn)入阻塞狀態(tài),我們可以將等待通知的任務(wù)看作是消費(fèi)者;其它任務(wù)和中斷可以向等待通知的任務(wù)發(fā)送通知,發(fā)送通知的任務(wù)和中斷服務(wù)函數(shù)可以認(rèn)為是生產(chǎn)者。處于阻塞的消費(fèi)者得到通知后會(huì)再次進(jìn)入就緒態(tài)。

任務(wù)通知API函數(shù)主要有兩類,一類發(fā)送通知,一類等待通知。發(fā)送通知API函數(shù)可以用于任務(wù)和中斷服務(wù)函數(shù),等待通知API函數(shù)只能用在任務(wù)中。

1.發(fā)送通知

我們先看一下發(fā)送通知API函數(shù)。這類函數(shù)比較多,有6個(gè)。但仔細(xì)分析會(huì)發(fā)現(xiàn)它們只能完成3種操作,每種操作有兩個(gè)API函數(shù),分別為帶中斷保護(hù)版本和不帶中斷保護(hù)版本。FreeRTOS將API細(xì)分為帶中斷保護(hù)版本和不帶中斷保護(hù)版本是為了節(jié)省中斷服務(wù)程序處理時(shí)間,提升性能。
和信號(hào)量類似,大多數(shù)發(fā)送通知API接口也是由宏實(shí)現(xiàn)的,如表1-1所示。

表1-1:發(fā)送通知API函數(shù)與實(shí)際調(diào)用函數(shù)列表

1.1 xTaskGenericNotify()

不帶中斷保護(hù)的發(fā)送通知API函數(shù)實(shí)際都是調(diào)用函數(shù)xTaskGenericNotify()實(shí)現(xiàn)的,我們看一下這個(gè)函數(shù)原型:

BaseType_t xTaskGenericNotify( 
        TaskHandle_t xTaskToNotify, 
        uint32_t ulValue, 
        eNotifyAction eAction, 
        uint32_t *pulPreviousNotificationValue )

xTaskToNotify:被通知的任務(wù)句柄。

ulValue:更新的通知值

eAction:枚舉類型,指明更新通知值的方法,枚舉變量成員以及作用見表1-2所示。

pulPreviousNotifyValue:回傳未被更新的任務(wù)通知值。如果不需要回傳未被更新的任務(wù)通知值,這里設(shè)置為NULL。

表1-2:eNotifyAction枚舉成員以及作用

與入隊(duì)操作相比較,發(fā)送通知API函數(shù)顯得非常簡單,整理后的源碼如下所示:

BaseType_t xTaskGenericNotify( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue )
{
TCB_t * pxTCB;
BaseType_t xReturn = pdPASS;
uint8_t ucOriginalNotifyState;
    configASSERT( xTaskToNotify );
    pxTCB = ( TCB_t * ) xTaskToNotify;
    taskENTER_CRITICAL();
    {
        if( pulPreviousNotificationValue != NULL )
        {
			/* 回傳更新前的通知值*/
            *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
        }
        ucOriginalNotifyState = pxTCB->ucNotifyState;
        pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
         switch( eAction )
        {
            case eSetBits   :
                pxTCB->ulNotifiedValue |= ulValue;
                break;
            case eIncrement :
                ( pxTCB->ulNotifiedValue )++;
                break;
            case eSetValueWithOverwrite :
                pxTCB->ulNotifiedValue = ulValue;
                break;
            case eSetValueWithoutOverwrite :
                if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
                {
                    pxTCB->ulNotifiedValue = ulValue;
                }
                else
                {
                    /* 上次的通知值還未取走,本次通知值丟棄 */
                    xReturn = pdFAIL;
                }
                break;
            case eNoAction:
                /* 不需要更新通知值*/
                break;
        }
        traceTASK_NOTIFY();
         /* 如果被通知的任務(wù)因?yàn)榈却ㄖ枞?現(xiàn)在將它解除阻塞 */
        if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
        {
            ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
            prvAddTaskToReadyList( pxTCB );
            if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
            {
                /* 如果被通知的任務(wù)優(yōu)先級(jí)高于當(dāng)前任務(wù),則觸發(fā)PendSV中斷,退出臨界區(qū)后進(jìn)行上下文切換T*/
                taskYIELD_IF_USING_PREEMPTION();
            }
        }
    }
    taskEXIT_CRITICAL();
     return xReturn;
}

函數(shù)的功能可以概括為:按照指定的方法更新通知值,如果被通知的任務(wù)處于阻塞狀態(tài),則將它解除阻塞,解除阻塞任務(wù)的優(yōu)先級(jí)如果大于當(dāng)前任務(wù)的優(yōu)先級(jí),則觸發(fā)一次任務(wù)切換。

與釋放信號(hào)量API函數(shù)相比,本函數(shù)少了很多調(diào)用子函數(shù)開銷、少了很多判斷、少了對(duì)事件列表的操作等等,確實(shí)是比釋放信號(hào)量的實(shí)現(xiàn)要簡潔的多。這也是有原因的,因?yàn)槿蝿?wù)通知有它自己的局限性,并不能完全代替信號(hào)量。比如一個(gè)任務(wù)只能阻塞到一個(gè)通知上,如想要實(shí)現(xiàn)多個(gè)任務(wù)阻塞到同一個(gè)事件上,只能使用信號(hào)量了。也正是因?yàn)檫@種局限性,使得任務(wù)通知實(shí)現(xiàn)起來簡單高效,并且大多數(shù)情況下,任務(wù)通知的方法就已經(jīng)能解決問題了。

1.2 vTaskNotifyGiveFromISR()

這個(gè)API函數(shù)是vTaskNotifyGive()的帶中斷保護(hù)版本,是專門設(shè)計(jì)用來在某些情況下代替二進(jìn)制信號(hào)量和計(jì)數(shù)信號(hào)量的。函數(shù)也很簡單,我們直接看源碼,源碼經(jīng)過整理和注釋,以方便理解。

void vTaskNotifyGiveFromISR( TaskHandle_t xTaskToNotify, BaseType_t *pxHigherPriorityTaskWoken )
{
TCB_t * pxTCB;
uint8_t ucOriginalNotifyState;
UBaseType_t uxSavedInterruptStatus;
    pxTCB = ( TCB_t * ) xTaskToNotify;
    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        ucOriginalNotifyState = pxTCB->ucNotifyState;
        pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
        /* 通知值加1,相當(dāng)于釋放了一個(gè)信號(hào)量 */
        ( pxTCB->ulNotifiedValue )++;
        /* 如果目標(biāo)任務(wù)因?yàn)榈却ㄖ枞?現(xiàn)在將它解除阻塞*/
        if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
        {
            /* 如果調(diào)度器正常,將任務(wù)放入就緒列表,否則放入掛起就緒列表 */
            if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
            {
                ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
                prvAddTaskToReadyList( pxTCB );
            }
            else
            {
                vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
            }
            if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
            {
                /* 如果解除阻塞的任務(wù)優(yōu)先級(jí)大于當(dāng)前任務(wù)優(yōu)先級(jí),則設(shè)置上下文切換標(biāo)識(shí),等退出函數(shù)后手動(dòng)切換上下文,或者在系統(tǒng)節(jié)拍中斷服務(wù)程序中自動(dòng)切換上下文*/
                if( pxHigherPriorityTaskWoken != NULL )
                {
                    *pxHigherPriorityTaskWoken = pdTRUE;    /* 設(shè)置手動(dòng)切換標(biāo)志 */
                }
                else
                {
                    xYieldPending = pdTRUE;                 /* 設(shè)置自動(dòng)切換標(biāo)志 */
                }
            }
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
}

1.3 xTaskGenericNotifyFromISR()

如表1-1所示,帶中斷保護(hù)版本的API函數(shù)xTaskNotifyFromISR()和xTaskNotifyAndQueryFromISR()都是宏定義,真正被調(diào)用的函數(shù)為xTaskGenericNotifyFromISR()。

這個(gè)函數(shù)用于在中斷在中發(fā)送通知,與不帶中斷保護(hù)的API函數(shù)xTaskGenericNotify()非常相似,只是增加了一些中斷保護(hù)措施,我們直接看源碼。通用源碼經(jīng)過整理和注釋,以方便理解。

BaseType_t xTaskGenericNotifyFromISR( TaskHandle_t xTaskToNotify, uint32_t ulValue, eNotifyAction eAction, uint32_t *pulPreviousNotificationValue, BaseType_t *pxHigherPriorityTaskWoken )
{
TCB_t * pxTCB;
uint8_t ucOriginalNotifyState;
BaseType_t xReturn = pdPASS;
UBaseType_t uxSavedInterruptStatus;
    pxTCB = ( TCB_t * ) xTaskToNotify;
    uxSavedInterruptStatus = portSET_INTERRUPT_MASK_FROM_ISR();
    {
        if( pulPreviousNotificationValue != NULL )
        {
            /* 回傳更新前的通知值 */
            *pulPreviousNotificationValue = pxTCB->ulNotifiedValue;
        }
        ucOriginalNotifyState = pxTCB->ucNotifyState;
        pxTCB->ucNotifyState = taskNOTIFICATION_RECEIVED;
        /* 根據(jù)參數(shù)設(shè)置通知值 */
        switch( eAction )
        {
            case eSetBits   :
                pxTCB->ulNotifiedValue |= ulValue;
                break;
            case eIncrement :
                ( pxTCB->ulNotifiedValue )++;
                break;
            case eSetValueWithOverwrite :
                pxTCB->ulNotifiedValue = ulValue;
                break;
            case eSetValueWithoutOverwrite :
                if( ucOriginalNotifyState != taskNOTIFICATION_RECEIVED )
                {
                    pxTCB->ulNotifiedValue = ulValue;
                }
                else
                {
                    /* 上次的通知值還未取走,本次通知值丟棄 */
                    xReturn = pdFAIL;
                }
                break;
            case eNoAction :
                /* 不需要更新通知值*/
                break;
        }
        traceTASK_NOTIFY_FROM_ISR();
        /* 如果被通知的任務(wù)因?yàn)榈却ㄖ枞?現(xiàn)在將它解除阻塞 */
        if( ucOriginalNotifyState == taskWAITING_NOTIFICATION )
        {   
            /* 如果調(diào)度器正常,將任務(wù)放入就緒列表,否則放入掛起就緒列表 */
            if( uxSchedulerSuspended == ( UBaseType_t ) pdFALSE )
            {
                ( void ) uxListRemove( &( pxTCB->xStateListItem ) );
                prvAddTaskToReadyList( pxTCB );
            }
            else
            {
                vListInsertEnd( &( xPendingReadyList ), &( pxTCB->xEventListItem ) );
            }
             if( pxTCB->uxPriority > pxCurrentTCB->uxPriority )
            {
                /* 如果解除阻塞的任務(wù)優(yōu)先級(jí)大于當(dāng)前任務(wù)優(yōu)先級(jí),則設(shè)置上下文切換標(biāo)識(shí),等退出函數(shù)后手動(dòng)切換上下文,或者在系統(tǒng)節(jié)拍中斷服務(wù)程序中自動(dòng)切換上下文*/
                if( pxHigherPriorityTaskWoken != NULL )
                {
                    *pxHigherPriorityTaskWoken = pdTRUE;    /* 設(shè)置手動(dòng)切換標(biāo)志 */
                }
                else
                {
                    xYieldPending = pdTRUE;                 /* 設(shè)置自動(dòng)切換標(biāo)志 */
                }
            }
        }
    }
    portCLEAR_INTERRUPT_MASK_FROM_ISR( uxSavedInterruptStatus );
    return xReturn;
}

2.等待通知

等待通知API函數(shù)只能用在任務(wù)中,沒有帶中斷保護(hù)版本,因此只有兩個(gè)API函數(shù):

ulTaskNotifyTake()和xTaskNotifyWait ()

前者是為代替二進(jìn)制信號(hào)量和計(jì)數(shù)信號(hào)量而專門設(shè)計(jì)的,它和發(fā)送通知API函數(shù)xTaskNotifyGive()、vTaskNotifyGiveFromISR()配合使用;

后者是全功能版的等待通知,可以根據(jù)不同的參數(shù)實(shí)現(xiàn)輕量級(jí)二進(jìn)制信號(hào)量、計(jì)數(shù)信號(hào)量、事件組和長度為1的隊(duì)列。

等待通知API函數(shù)都帶有最大阻塞時(shí)間參數(shù),當(dāng)任務(wù)因?yàn)榈却ㄖM(jìn)入阻塞時(shí),用來規(guī)定最大阻塞時(shí)間。

2.1 ulTaskNotifyTake()

這個(gè)API函數(shù)用于實(shí)現(xiàn)輕量級(jí)的二進(jìn)制信號(hào)量和計(jì)數(shù)信號(hào)量,源碼如下所示。它有兩個(gè)參數(shù),如果第一個(gè)參數(shù)xClearCountOnExit設(shè)置為pdTRUE,則用來實(shí)現(xiàn)二進(jìn)制信號(hào)量,函數(shù)退出時(shí)將通知值清零;如果第一個(gè)參數(shù)設(shè)置為pdFALSE,則用來實(shí)現(xiàn)計(jì)數(shù)信號(hào)量,函數(shù)退出時(shí),將通知值減一。

uint32_t ulTaskNotifyTake( BaseType_t xClearCountOnExit, TickType_t xTicksToWait )
{
uint32_t ulReturn;
    taskENTER_CRITICAL();
    {
        /* 僅當(dāng)通知值為0,才進(jìn)行阻塞操作*/
        if( pxCurrentTCB->ulNotifiedValue == 0UL )
        {
            /* 設(shè)置標(biāo)志,表示當(dāng)前任務(wù)等待一個(gè)通知*/
            pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;
            if( xTicksToWait > ( TickType_t ) 0 )
            {   
                /* 將任務(wù)加入延時(shí)列表 */
                prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
                traceTASK_NOTIFY_TAKE_BLOCK();
                /* 觸發(fā)PendSV中斷,等到退出臨界區(qū)時(shí)立即執(zhí)行任務(wù)切換 */
                portYIELD_WITHIN_API();
            }
        }
    }
    taskEXIT_CRITICAL();
    /* 到這里說明其它任務(wù)或中斷向這個(gè)任務(wù)發(fā)送了通知,或者任務(wù)阻塞超時(shí),現(xiàn)在繼續(xù)處理*/
    taskENTER_CRITICAL();
    {
        traceTASK_NOTIFY_TAKE();
        ulReturn = pxCurrentTCB->ulNotifiedValue;   
        if( ulReturn != 0UL )
        {
            if( xClearCountOnExit != pdFALSE )
            {
                pxCurrentTCB->ulNotifiedValue = 0UL;
            }
            else
            {
                pxCurrentTCB->ulNotifiedValue = ulReturn - 1;
            }
        }
        /* 設(shè)置標(biāo)志,表示不需要等待通知 */
        pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
    }
    taskEXIT_CRITICAL();
    return ulReturn;    /* 如果返回值為0,說明是任務(wù)阻塞超時(shí)了 */
}

與獲取二進(jìn)制信號(hào)量和獲取計(jì)數(shù)信號(hào)量函數(shù)相比,本函數(shù)少了很多調(diào)用子函數(shù)開銷、少了很多判斷、少了事件列表處理、少了隊(duì)列上鎖與解鎖處理等等,因此本函數(shù)相對(duì)效率很高。

2.2 xTaskNotifyWait()

這個(gè)函數(shù)用于實(shí)現(xiàn)全功能版的等待通知,根據(jù)參數(shù)的不同,可以靈活的用于實(shí)現(xiàn)輕量級(jí)的隊(duì)列、二進(jìn)制信號(hào)量、計(jì)數(shù)信號(hào)量和事件組功能,函數(shù)原型為:

BaseType_t xTaskNotifyWait( uint32_tulBitsToClearOnEntry,
                     uint32_tulBitsToClearOnExit,
                     uint32_t*pulNotificationValue,
                     TickType_txTicksToWait );

ulBitsToClearOnEntry:在使用通知之前,先將任務(wù)的通知值與參數(shù)ulBitsToClearOnEntry的按位取反值按位與操作。設(shè)置參數(shù)ulBitsToClearOnEntry為0xFFFFFFFF(ULONG_MAX),表示清零任務(wù)通知值。

ulBitsToClearOnExit:在函數(shù)xTaskNotifyWait()退出前,將任務(wù)的通知值與參數(shù)ulBitsToClearOnExit的按位取反值按位與操作。設(shè)置參數(shù)ulBitsToClearOnExit為0xFFFFFFFF(ULONG_MAX),表示清零任務(wù)通知值。

pulNotificationValue:用于向外回傳任務(wù)的通知值。這個(gè)通知值在參數(shù)ulBitsToClearOnExit起作用前將通知值拷貝到*pulNotificationValue中。如果不需要返回任務(wù)的通知值,這里設(shè)置成NULL。

xTicksToWait:因等待通知而進(jìn)入阻塞狀態(tài)的最大時(shí)間。時(shí)間單位為系統(tǒng)節(jié)拍周期。宏pdMS_TO_TICKS用于將指定的毫秒時(shí)間轉(zhuǎn)化為相應(yīng)的系統(tǒng)節(jié)拍數(shù)。

這個(gè)函數(shù)的實(shí)現(xiàn)和ulTaskNotifyTake()有很多相通之處,我將整個(gè)流程以注釋形式置于源碼中,源碼如下所示:

BaseType_t xTaskNotifyWait( uint32_t ulBitsToClearOnEntry, uint32_t ulBitsToClearOnExit, uint32_t *pulNotificationValue, TickType_t xTicksToWait )
{
BaseType_t xReturn;
    taskENTER_CRITICAL();
    {
        /* 只有任務(wù)沒有等待通知,才會(huì)將任務(wù)阻塞 */
        if( pxCurrentTCB->ucNotifyState != taskNOTIFICATION_RECEIVED )
        {
            /* 使用任務(wù)通知值之前,先將參數(shù)ulBitsToClearOnEntryClear取反后與任務(wù)通知值位與.可以用這種方法在使用任務(wù)通知值之前,將通知值的某些或全部位清零 */
            pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnEntry;
            /* 設(shè)置任務(wù)狀態(tài)標(biāo)識(shí):等待通知 */
            pxCurrentTCB->ucNotifyState = taskWAITING_NOTIFICATION;
            if( xTicksToWait > ( TickType_t ) 0 )
            {
                /* 阻塞當(dāng)前任務(wù) */
                prvAddCurrentTaskToDelayedList( xTicksToWait, pdTRUE );
                traceTASK_NOTIFY_WAIT_BLOCK();
                /* 觸發(fā)PendSV中斷,等到退出臨界區(qū)后,執(zhí)行任務(wù)切換 */
                portYIELD_WITHIN_API();
            }
        }
    }
    taskEXIT_CRITICAL();
    /* 到這里說明其它任務(wù)或中斷向這個(gè)任務(wù)發(fā)送了通知,或者任務(wù)阻塞超時(shí),現(xiàn)在繼續(xù)處理*/
    taskENTER_CRITICAL();
    {
        traceTASK_NOTIFY_WAIT();
        if( pulNotificationValue != NULL )
        {
            /* 輸出當(dāng)前通知值,通過指針參數(shù)傳遞*/
            *pulNotificationValue = pxCurrentTCB->ulNotifiedValue;
        }
         /* 判斷是否是因?yàn)槿蝿?wù)阻塞超時(shí) */
        if( pxCurrentTCB->ucNotifyState == taskWAITING_NOTIFICATION )
        {
            /* 沒有收到任務(wù)通知,是阻塞超時(shí) */
            xReturn = pdFALSE;
        }
        else
        {
            /* 收到任務(wù)值,先將參數(shù)ulBitsToClearOnExit取反后與通知值位與,用于在退出函數(shù)前,將通知值的某些或者全部位清零. */
            pxCurrentTCB->ulNotifiedValue &= ~ulBitsToClearOnExit;
            xReturn = pdTRUE;
        }
        /* 更改任務(wù)通知狀態(tài),解除任務(wù)通知等待 */
        pxCurrentTCB->ucNotifyState = taskNOT_WAITING_NOTIFICATION;
    }
    taskEXIT_CRITICAL();
    return xReturn;
}

縱觀整個(gè)任務(wù)通知的實(shí)現(xiàn),可以發(fā)現(xiàn)它比隊(duì)列、信號(hào)量相比要簡單很多。它可以實(shí)現(xiàn)輕量級(jí)的隊(duì)列、二進(jìn)制信號(hào)量、計(jì)數(shù)信號(hào)量和事件組,并且使用更方便、更節(jié)省RAM、更高效。FreeRTOS的作者做過測(cè)試,在同一平臺(tái)下,使用使用GCC編譯器、-o2優(yōu)化級(jí)別,相比使用信號(hào)量解除任務(wù)阻塞,使用任務(wù)通知可以快45%!這個(gè)性能的提升是巨大的。

我們分析過信號(hào)量的源碼,今天又分析了任務(wù)通知的源碼,這使得我們知道,之所以有這么大的性能提升,一方面緣于任務(wù)通知數(shù)據(jù)結(jié)構(gòu)簡單、實(shí)現(xiàn)簡潔;

另一方面也跟FreeRTOS的信號(hào)量機(jī)制臃腫、效率低下有關(guān)。因?yàn)樾盘?hào)量的實(shí)現(xiàn)全部是使用隊(duì)列機(jī)制,并沒有為信號(hào)量做專門優(yōu)化。

此外,著重說明一下任務(wù)通知并不能完全代替隊(duì)列、二進(jìn)制信號(hào)量、計(jì)數(shù)信號(hào)量和事件組,任務(wù)通知有自己的局限性,我們就以它的局限性來結(jié)束本文:

只能有一個(gè)任務(wù)接收通知事件。

接收通知的任務(wù)可以因?yàn)榈却ㄖM(jìn)入阻塞狀態(tài),但是發(fā)送通知的任務(wù)即便不能立即完成發(fā)送通知,也不能進(jìn)入阻塞狀態(tài)。

以上就是FreeRTOS進(jìn)階任務(wù)通知示例分析的詳細(xì)內(nèi)容,更多關(guān)于FreeRTOS任務(wù)通知分析的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

最新評(píng)論