FreeRTOS進(jìn)階之任務(wù)通知示例完全解析
前言
在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)文章
FreeRTOS實(shí)時(shí)操作系統(tǒng)結(jié)構(gòu)示例
這篇文章主要介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)結(jié)構(gòu)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)臨界段保護(hù)場(chǎng)合示例
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)臨界段保護(hù)場(chǎng)合示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)Cortex-M內(nèi)核使用注意事項(xiàng)
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)Cortex-M內(nèi)核使用注意事項(xiàng),有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階之系統(tǒng)延時(shí)完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階之系統(tǒng)延時(shí)完全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階之空閑任務(wù)示例完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階之空閑任務(wù)示例的完全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS進(jìn)階系統(tǒng)節(jié)拍時(shí)鐘示例的完全解析
這篇文章主要為大家介紹了FreeRTOS進(jìn)階系統(tǒng)節(jié)拍時(shí)鐘示例的完全解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)概要講解
這篇文章主要為大家介紹了FreeRTOS實(shí)時(shí)操作系統(tǒng)的任務(wù)概要講解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步早日升職加薪2022-04-04