日本搞逼视频_黄色一级片免费在线观看_色99久久_性明星video另类hd_欧美77_综合在线视频

國內(nèi)最全IT社區(qū)平臺 聯(lián)系我們 | 收藏本站
阿里云優(yōu)惠2
您當前位置:首頁 > php開源 > 綜合技術(shù) > FreeRTOS高級篇6---FreeRTOS信號量分析

FreeRTOS高級篇6---FreeRTOS信號量分析

來源:程序員人生   發(fā)布時間:2016-06-25 15:35:06 閱讀次數(shù):14513次

         FreeRTOS的信號量包括2進制信號量、計數(shù)信號量、互斥信號量(以后簡稱互斥量)和遞歸互斥信號量(以后簡稱遞歸互斥量)。關(guān)于它們的區(qū)分可以參考《 FreeRTOS系列第19篇---FreeRTOS信號量》1文。

         信號量API函數(shù)實際上都是宏,它使用現(xiàn)有的隊列機制。這些宏定義在semphr.h文件中。如果使用信號量或互斥量,需要包括semphr.h頭文件。

        2進制信號量、計數(shù)信號量和互斥量信號量的創(chuàng)建API函數(shù)是獨立的,但是獲得和釋放API函數(shù)都是相同的;遞歸互斥信號量的創(chuàng)建、獲得和釋放API函數(shù)都是獨立的。

1.信號量創(chuàng)建

         在《FreeRTOS高級篇5---FreeRTOS隊列分析》中,我們分析了隊列的實現(xiàn)進程,包括隊列創(chuàng)建、入隊和出隊操作。在那篇文章中我們說過,創(chuàng)建隊列API函數(shù)實際是調(diào)用通用隊列創(chuàng)建函數(shù)xQueueGenericCreate()來實現(xiàn)的。其實,不但創(chuàng)建隊列實際調(diào)用通用隊列創(chuàng)建函數(shù),2進制信號量、計數(shù)信號量、互斥量和遞歸互斥量也都直接或間接使用這個函數(shù),如表1⑴所示。表1⑴中紅色字體表示是間接調(diào)用xQueueGenericCreate()函數(shù)。

表1⑴:隊列、信號量和互斥量創(chuàng)建宏與直接(間接)履行函數(shù)

 

1.1.創(chuàng)建2進制信號量

         2進制信號量創(chuàng)建實際上是直接使用通用隊列創(chuàng)建函數(shù)xQueueGenericCreate()。創(chuàng)建2進制信號量API接口實際上是1個宏,定義以下:

#define xSemaphoreCreateBinary() \ xQueueGenericCreate( \ ( UBaseType_t ) 1, \ semSEMAPHORE_QUEUE_ITEM_LENGTH, \ NULL, \ NULL, \ queueQUEUE_TYPE_BINARY_SEMAPHORE\ )

        通過這個宏定義我們知道創(chuàng)建2進制信號量實際上是創(chuàng)建了1個隊列,隊列項有1個,但是隊列項的大小為0(宏semSEMAPHORE_QUEUE_ITEM_LENGTH定義為0)。

有了隊列創(chuàng)建的知識,我們可以很容易的畫出初始化后的2進制信號量內(nèi)存,如圖1⑴所示。


圖1⑴:初始化后的2進制信號量對象內(nèi)存

        也許不止1人像我1樣奇怪,創(chuàng)建1個沒有隊列項存儲空間的隊列,信號量用甚么表示?其實2進制信號量的釋放和獲得都是通過操作隊列結(jié)構(gòu)體成員uxMessageWaiting來實現(xiàn)的(圖1⑴紅色部份,uxMessageWaiting表示隊列中當前隊列項的個數(shù))。經(jīng)過初始化后,變量uxMessageWaiting為0,這說明隊列為空,也就是信號量處于無效狀態(tài)。在使用API函數(shù)xSemaphoreTake()獲得信號之前,需要先釋放1個信號量。后面講到2進制信號量釋放和獲得時還會詳細介紹。

1.2.創(chuàng)建計數(shù)信號量

         創(chuàng)建計數(shù)信號量間接使用通用隊列創(chuàng)建函數(shù)xQueueGenericCreate()。創(chuàng)建計數(shù)信號量API接口一樣是個宏定義:

#define xSemaphoreCreateCounting(uxMaxCount, uxInitialCount ) \ xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ), (NULL ) )

         創(chuàng)建計數(shù)信號量API接口有兩個參數(shù),含義以下:

  • uxMaxCount:最大計數(shù)值,當信號到達這個值后,就不再增長了。
  • uxInitialCount:創(chuàng)建信號量時的初始值。

         我們來看1下函數(shù)xQueueCreateCountingSemaphore()如何實現(xiàn)的:

QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_tuxMaxCount, const UBaseType_t uxInitialCount, StaticQueue_t *pxStaticQueue ) { QueueHandle_t xHandle; configASSERT( uxMaxCount != 0 ); configASSERT( uxInitialCount <= uxMaxCount ); /*調(diào)用通用隊列創(chuàng)建函數(shù)*/ xHandle =xQueueGenericCreate( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH, NULL, pxStaticQueue, queueQUEUE_TYPE_COUNTING_SEMAPHORE ); if( xHandle != NULL ) { ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount; } configASSERT( xHandle ); return xHandle; }

         從代碼可以看出,創(chuàng)建計數(shù)信號量依然調(diào)用通用隊列創(chuàng)建函數(shù)xQueueGenericCreate()來創(chuàng)建1個隊列,隊列項的數(shù)目由參數(shù)uxMaxCount指定,每一個隊列項的大小由宏queueSEMAPHORE_QUEUE_ITEM_LENGTH指出,我們找到這個宏定義發(fā)現(xiàn),這個宏被定義為0,也就是說創(chuàng)建的隊列只有隊列數(shù)據(jù)結(jié)構(gòu)存儲空間而沒有隊列項存儲空間。

         如果隊列創(chuàng)建成功,則將隊列結(jié)構(gòu)體成員uxMessageWaiting設(shè)置為初始計數(shù)信號量值。初始化后的計數(shù)信號量內(nèi)存如圖3⑴所示。


圖1⑵:初始化后的計數(shù)信號量對象內(nèi)存

1.3創(chuàng)建互斥量

         創(chuàng)建互斥量間接使用通用隊列創(chuàng)建函數(shù)xQueueGenericCreate()。創(chuàng)建互斥量API接口一樣是個宏,定義以下:

#define xSemaphoreCreateMutex() \ xQueueCreateMutex( queueQUEUE_TYPE_MUTEX, NULL )

         其中,宏queueQUEUE_TYPE_MUTEX用于通用隊列創(chuàng)建函數(shù),表示創(chuàng)建隊列的類型是互斥量,在文章《FreeRTOS高級篇5---FreeRTOS隊列分析》關(guān)于通用隊列創(chuàng)建函數(shù)參數(shù)說明中提到了這個宏。

         我們來看1下函數(shù)xQueueCreateMutex()是如何實現(xiàn)的:

#if ( configUSE_MUTEXES == 1 ) QueueHandle_t xQueueCreateMutex( const uint8_tucQueueType, StaticQueue_t *pxStaticQueue ) { Queue_t *pxNewQueue; const UBaseType_tuxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; /* 避免編譯器產(chǎn)生正告信息 */ ( void ) ucQueueType; /*調(diào)用通用隊列創(chuàng)建函數(shù)*/ pxNewQueue = ( Queue_t * )xQueueGenericCreate( uxMutexLength, uxMutexSize, NULL, pxStaticQueue, ucQueueType ); /* 成功分配新的隊列結(jié)構(gòu)體? */ if( pxNewQueue != NULL ) { /*xQueueGenericCreate()函數(shù)會依照通用隊列的方式設(shè)置所有隊列結(jié)構(gòu)體成員,但是我們是要創(chuàng)建互斥量.因此需要對1些結(jié)構(gòu)體成員重新賦值. */ pxNewQueue->pxMutexHolder = NULL; pxNewQueue->uxQueueType =queueQUEUE_IS_MUTEX; //NULL /* 用于遞歸互斥量創(chuàng)建 */ pxNewQueue->u.uxRecursiveCallCount = 0; /* 使用1個預期狀態(tài)啟動信號量 */ ( void ) xQueueGenericSend( pxNewQueue, NULL, ( TickType_t ) 0U, queueSEND_TO_BACK); } return pxNewQueue; } #endif /* configUSE_MUTEXES */

         這個函數(shù)是帶條件編譯的,只有將宏configUSE_MUTEXES定義為1才會編譯這個函數(shù)。

         函數(shù)首先調(diào)用通用隊列創(chuàng)建函數(shù)xQueueGenericCreate()來創(chuàng)建1個隊列,隊列項數(shù)目為1,隊列項大小為0,說明創(chuàng)建的隊列只有隊列數(shù)據(jù)結(jié)構(gòu)存儲空間而沒有隊列項存儲空間。

         如果隊列創(chuàng)建成功,通用隊列創(chuàng)建函數(shù)還會依照通用隊列的方式 初始化所有隊列結(jié)構(gòu)體成員。但是這里要創(chuàng)建的是互斥量,所以有1些結(jié)構(gòu)體成員必須重新賦值。在這段代碼中,可能你會疑惑,隊列結(jié)構(gòu)體成員中,并沒有pxMutexHolder和uxQueueType!其實這兩個標識符只是宏定義,是專門為互斥量而定義的,以下所示:

#define pxMutexHolder pcTail #define uxQueueType pcHead #define queueQUEUE_IS_MUTEX NULL

         當隊列結(jié)構(gòu)體用于互斥量時,成員pcHead和pcTail指針就不再需要,并且將pcHead指針設(shè)置為NULL,表示pcTail指針實際指向互斥量持有者任務(wù)TCB(如果有的話)。

         最后調(diào)用函數(shù)xQueueGenericSend()釋放1個互斥量,相當于互斥量創(chuàng)建后是有效的,可以直接使用獲得信號量API函數(shù)來獲得這個互斥量。如果某資源同時只準1個任務(wù)訪問,可以用互斥量保護這個資源。這個資源1定是存在的,所以創(chuàng)建互斥量時會先釋放1個互斥量,表示這個資源可使用。任務(wù)想訪問資源時,先獲得互斥量,等使用完資源后,再釋放它。也就是說互斥量1旦創(chuàng)建好后,要先獲得,后釋放,要在同1個任務(wù)中獲得和釋放。這也是互斥量和2進制信號量的1個重要區(qū)分,2進制信號量可以在隨意1個任務(wù)中獲得或釋放,然后也能夠在任意1個任務(wù)中釋放或獲得。互斥量不同于2進制信號量的還有:互斥量具有優(yōu)先級繼承機制,2進制信號量沒有,互斥量不可以用于中斷服務(wù)程序,2進制信號量可以。

初始化后的互斥量內(nèi)存如圖1⑶所示。


圖1⑶:初始化后的互斥量對象內(nèi)存

1.4創(chuàng)建遞歸互斥量

         創(chuàng)建遞歸互斥量間接使用通用隊列創(chuàng)建函數(shù)xQueueGenericCreate()。創(chuàng)建遞歸互斥量API接口一樣是個宏,定義以下:

#definexSemaphoreCreateRecursiveMutex() \ xQueueCreateMutex(queueQUEUE_TYPE_RECURSIVE_MUTEX, NULL )

         其中,宏queueQUEUE_TYPE_RECURSIVE_MUTEX用于通用隊列創(chuàng)建函數(shù),表示創(chuàng)建隊列的類型是遞歸互斥量,在文章《FreeRTOS高級篇5---FreeRTOS隊列分析》關(guān)于通用隊列創(chuàng)建函數(shù)參數(shù)說明中提到了這個宏。

         創(chuàng)建互斥量和創(chuàng)建遞歸互斥量是調(diào)用的同1個函數(shù)xQueueCreateMutex(),至于參數(shù)queueQUEUE_TYPE_RECURSIVE_MUTEX,我們在FreeRTOS1文中已知道,它只是用于可視化調(diào)試,因此創(chuàng)建互斥量和創(chuàng)建遞歸互斥量可以看做是1樣的,初始化后的遞歸互斥量對象內(nèi)存也和互斥量1樣,如圖1⑶所示。

2.釋放信號量

         不管2進制信號量、計數(shù)信號量還是互斥量,它們都使用相同的獲得和釋放API函數(shù)。釋放信號量用于使信號量有效,分為不帶中斷保護和帶中斷保護兩個版本。

2.1 xSemaphoreGive()

         用于釋放1個信號量,不帶中斷保護。被釋放的信號量可以是2進制信號量、計數(shù)信號量和互斥量。注意遞歸互斥量其實不能使用這個API函數(shù)釋放。其實信號量釋放是1個宏,真正調(diào)用的函數(shù)是xQueueGenericSend(),宏定義以下:

#definexSemaphoreGive( xSemaphore ) \ xQueueGenericSend( \ ( QueueHandle_t ) ( xSemaphore ), \ NULL, \ semGIVE_BLOCK_TIME, \ queueSEND_TO_BACK )

         可以看出釋放信號量實際上是1次入隊操作,并且阻塞時間為0(由宏semGIVE_BLOCK_TIME定義)。

         對2進制信號量和計數(shù)信號量,根據(jù)上1章的內(nèi)容可以總結(jié)出,釋放1個信號量的進程實際上可以簡化為兩種情況:第1,如果隊列未滿,隊列結(jié)構(gòu)體成員uxMessageWaiting加1,判斷是不是有阻塞的任務(wù),有的話消除阻塞,然后返回成功信息(pdPASS);第2,如果隊列滿,返回毛病代碼(err_QUEUE_FULL),表示隊列滿。

        對互斥量要復雜些,由于互斥量具有優(yōu)先級繼承機制。

        優(yōu)先級繼承是個甚么進程呢?我們舉個例子。某個資源X同時只能有1個任務(wù)訪問,現(xiàn)在有任務(wù)A和任務(wù)C都要訪問這個資源,任務(wù)A的優(yōu)先級為1,任務(wù)C的優(yōu)先級為10,所以任務(wù)C的優(yōu)先級大于任務(wù)A的優(yōu)先級。我們用互斥量保護資源X,并且當前任務(wù)A正在訪問資源X。在任務(wù)A訪問資源X的進程中,來了1個中斷,中斷事件使得任務(wù)C履行。任務(wù)C履行的進程中,也想訪問資源X,但是由于資源X還被任務(wù)A獨占著,所以任務(wù)C沒法獲得互斥量,會進入阻塞狀態(tài)。此時,低優(yōu)先級任務(wù)A會繼承高優(yōu)先級任務(wù)C的優(yōu)先級,任務(wù)A的優(yōu)先級臨時的被提升,優(yōu)先級變成10。這個機制能夠?qū)⒁旬a(chǎn)生的優(yōu)先級反轉(zhuǎn)影響下降到最小。

        那末甚么是優(yōu)先級反轉(zhuǎn)呢?還是看上面的例子,任務(wù)C的優(yōu)先級高于任務(wù)A,但是任務(wù)C由于沒有取得互斥量而進入阻塞,只能等待低優(yōu)先級的任務(wù)A釋放互斥量后才能運行,這類情況就是優(yōu)先級反轉(zhuǎn)。

        那為何優(yōu)先級繼承可以下降優(yōu)先級反轉(zhuǎn)的影響呢?還是看上面的例子,不過我們再增加1個優(yōu)先級為5的任務(wù)B,這3個任務(wù)都處于就緒狀態(tài)。如果沒有優(yōu)先級繼承機制,3個任務(wù)的優(yōu)先級順序為任務(wù)C>任務(wù)B>任務(wù)A。當任務(wù)C由于得不到互斥量而阻塞后,任務(wù)B會獲得CPU權(quán)限,等到任務(wù)B主動或被動讓出CPU后,任務(wù)A才會履行,任務(wù)A釋放互斥量后,任務(wù)C才能得到運行。再看1下有優(yōu)先級繼承的情況,當任務(wù)C由于得不到互斥量而阻塞后,任務(wù)A繼承任務(wù)C的優(yōu)先級,現(xiàn)在3個任務(wù)的優(yōu)先級順序為任務(wù)C=任務(wù)A>任務(wù)B。當任務(wù)C由于得不到互斥量而阻塞后,任務(wù)A會取得CPU權(quán)限,等到任務(wù)A釋放互斥量后,任務(wù)C就會得到運行。看,任務(wù)C等待的時間變短了。

        有了上面的基礎(chǔ)理論,我們就很好理解為何釋放互斥量會比較復雜了。還是可以簡化為兩種情況:第1,如果隊列未滿,除隊列結(jié)構(gòu)體成員uxMessageWaiting加1外,還要判斷獲得互斥量的任務(wù)是不是有優(yōu)先級繼承,如果有的話,還要將任務(wù)的優(yōu)先級恢復到原始值。固然,恢復到原來值也是有條件的,就是該任務(wù)必須在沒有使用其它互斥量的情況下,才能將繼承的優(yōu)先級恢復到原始值。然后判斷是不是有阻塞的任務(wù),有的話消除阻塞,最后返回成功信息(pdPASS);第2,如果如果隊列滿,返回毛病代碼(err_QUEUE_FULL),表示隊列滿。

2.2xSemaphoreGiveFromISR()

         用于釋放1個信號量,帶中斷保護。被釋放的信號量可以是2進制信號量和計數(shù)信號量。和普通版本的釋放信號量API函數(shù)不同,它不能釋放互斥量,這是由于互斥量不可以在中斷中使用!互斥量的優(yōu)先級繼承機制只能在任務(wù)中起作用,在中斷中毫無意義。帶中斷保護的信號量釋放其實也是1個宏,真正調(diào)用的函數(shù)是xQueueGiveFromISR (),宏定義以下:

#definexSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \ xQueueGiveFromISR( \ ( QueueHandle_t ) ( xSemaphore), \ ( pxHigherPriorityTaskWoken ) )

        我們看真正被調(diào)用的函數(shù)源碼(經(jīng)過整理后的):   

BaseType_t xQueueGiveFromISR( QueueHandle_t xQueue, BaseType_t * constpxHigherPriorityTaskWoken ) { BaseType_t xReturn; UBaseType_t uxSavedInterruptStatus; Queue_t * const pxQueue = ( Queue_t * ) xQueue; uxSavedInterruptStatus =portSET_INTERRUPT_MASK_FROM_ISR(); { /*當隊列用于實現(xiàn)信號量時,永久不會有數(shù)據(jù)出入隊列,但是任然要檢查隊列是不是為空 */ if( pxQueue->uxMessagesWaiting < pxQueue->uxLength ) { /* 1個任務(wù)可以獲得多個互斥量,但是只能有1個繼承優(yōu)先級,如果任務(wù)是互斥量的持有者,則互斥量不允許在中斷服務(wù)程序中釋放.因此這里不需要判斷是不是要恢復任務(wù)的原始優(yōu)先級值,只是簡單更新隊列項計數(shù)器. */ ++( pxQueue->uxMessagesWaiting ); /* 如果列表上鎖,不能改變隊列的事件列表. */ if( pxQueue->xTxLock == queueUNLOCKED ) { if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive) ) == pdFALSE ) { if(xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive) ) != pdFALSE ) { /* 消除阻塞的任務(wù)有更高優(yōu)先級,因此記錄上下文切換要求*/ if(pxHigherPriorityTaskWoken != NULL ) { *pxHigherPriorityTaskWoken= pdTRUE; } } } } else { /* Increment thelock count so the task that unlocks the queue knows that data wasposted while it was locked. */ ++( pxQueue->xTxLock ); } xReturn = pdPASS; } else { xReturn = errQUEUE_FULL; } } portCLEAR_INTERRUPT_MASK_FROM_ISR(uxSavedInterruptStatus ); return xReturn; }

         由于不觸及互斥量,不觸及阻塞,函數(shù)xQueueGiveFromISR()異常簡單,如果隊列滿,直接返回毛病代碼(err_QUEUE_FULL);如果隊列未滿,則將隊列結(jié)構(gòu)體成員uxMessageWaiting加1,然后視隊列是不是上鎖而決定是不是消除任務(wù)阻塞(如果有得話)。如果你覺得難以理解,則需要先看看《FreeRTOS高級篇5---FreeRTOS隊列分析》。

3.獲得信號量

         不管2進制信號量、計數(shù)信號量還是互斥量,它們都使用相同的獲得和釋放API函數(shù)。釋獲得信號量會消耗信號量,如果獲得信號量失敗,任務(wù)可能會阻塞,阻塞時間由函數(shù)參數(shù)xBlockTime指定,如果為0,則直接返回,不阻塞。獲得信號量分為不帶中斷保護和帶中斷保護兩個版本。

3.1 xSemaphoreTake

         用于獲得信號量,不帶中斷保護。獲得的信號量可以是2進制信號量、計數(shù)信號量和互斥量。注意遞歸互斥量其實不能使用這個API函數(shù)獲得。其實獲得信號量是1個宏,真正調(diào)用的函數(shù)是xQueueGenericReceive (),宏定義以下:

#definexSemaphoreTake( xSemaphore, xBlockTime ) \ xQueueGenericReceive( \ ( QueueHandle_t ) ( xSemaphore ), \ NULL, \ ( xBlockTime ), \ pdFALSE )

         通過上面的宏定義可以看出,獲得信號量實際上是履行出隊操作。

         對2進制信號量和計數(shù)信號量,可以簡化為3種情況:第1,如果隊列不為空,隊列結(jié)構(gòu)體成員uxMessageWaiting減1,判斷是不是有因入隊而阻塞的任務(wù),有的話消除阻塞,然后返回成功信息(pdPASS);第2,如果隊列為空并且阻塞時間為0,則直接返回毛病碼(errQUEUE_EMPTY),表示隊列為空;第3,如果隊列為空并且阻塞時間不為0,則任務(wù)會由于等待信號量而進入阻塞狀態(tài),任務(wù)會被掛接到延時列表中。

        對互斥量,也能夠簡化為3種情況,但是進程要復雜1些:第1,如果隊列不為空,隊列結(jié)構(gòu)體成員uxMessageWaiting減1、將當前任務(wù)TCB結(jié)構(gòu)體成員uxMutexesHeld加1,表示任務(wù)獲得互斥量的個數(shù)、將隊列結(jié)構(gòu)體成員指針pxMutexHolder指向任務(wù)TCB、判斷是不是有因入隊而阻塞的任務(wù),有的話消除阻塞,然后返回成功信息(pdPASS);第2,如果隊列為空并且阻塞時間為0,則直接返回毛病碼(errQUEUE_EMPTY),表示隊列為空;第3,如果隊列為空并且阻塞時間不為0,則任務(wù)會由于等待信號量而進入阻塞狀態(tài),在將任務(wù)掛接到延時列表之前,會判斷當前任務(wù)和具有互斥量的任務(wù)優(yōu)先級哪一個高,如果當前任務(wù)優(yōu)先級高,則具有互斥量的任務(wù)繼承擔前任務(wù)優(yōu)先級。

3.2xSemaphoreTakeFromISR()

         用于獲得信號量,帶中斷保護。獲得的信號量可以是2進制信號量和計數(shù)信號量。和普通版本的獲得信號量API函數(shù)不同,它不能獲得互斥量,這是由于互斥量不可以在中斷中使用!互斥量的優(yōu)先級繼承機制只能在任務(wù)中起作用,在中斷中毫無意義。帶中斷保護的獲得信號量其實也是1個宏,真正調(diào)用的函數(shù)是xQueueReceiveFromISR (),宏定義以下:

#definexSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \ xQueueReceiveFromISR( \ ( QueueHandle_t ) ( xSemaphore ), \ NULL, \ ( pxHigherPriorityTaskWoken ) )

        一樣由于不觸及互斥量,不觸及阻塞,函數(shù)xQueueReceiveFromISR ()一樣異常簡單:如果隊列為空,直接返回毛病代碼(pdFAIL);如果隊列非空,則將隊列結(jié)構(gòu)體成員uxMessageWaiting減1,然后視隊列是不是上鎖而決定是不是消除任務(wù)阻塞(如果有得話)。

4.釋放遞歸互斥量

          函數(shù)xSemaphoreGiveRecursive()用于釋放1個遞歸互斥量。已獲得遞歸互斥量的任務(wù)可以重復獲得該遞歸互斥量。使用xSemaphoreTakeRecursive() 函數(shù)成功獲得幾次遞歸互斥量,就要使用xSemaphoreGiveRecursive()函數(shù)返還幾次,在此之前遞歸互斥量都處于無效狀態(tài)。比如,某個任務(wù)成功獲得5次遞歸互斥量,那末在它沒有返還5次該遞歸互斥量之前,這個互斥量對別的任務(wù)無效。

         像其它信號量1樣,xSemaphoreGiveRecursive()也是1個宏定義,它終究使用現(xiàn)有的隊列機制,實際履行的函數(shù)是xQueueGiveMutexRecursive(),這個宏定義以下所示:

#definexSemaphoreGiveRecursive( xMutex ) \ xQueueGiveMutexRecursive( (xMutex ) )  

         我們重點來看函數(shù)xQueueGiveMutexRecursive()的實現(xiàn)進程。經(jīng)過整理后(去除跟蹤調(diào)試語句)的源碼以下所示:

#if ( configUSE_RECURSIVE_MUTEXES == 1 ) BaseType_txQueueGiveMutexRecursive( QueueHandle_t xMutex ) { BaseType_t xReturn; Queue_t * const pxMutex = ( Queue_t * ) xMutex; /* 互斥量和遞歸互斥量要在同1個任務(wù)中獲得和釋放,當獲得互斥量或遞歸互斥量時,隊列結(jié)構(gòu)體成員指針pxMutexHolder指向獲得互斥量或遞歸互斥量的任務(wù)TCB,所以在釋放遞歸互斥量時需要檢查這個指針指向的TCB是不是是和當前任務(wù)TCB相同,如果不相同是不能釋放這個遞歸互斥量的! 注:釋放互斥量時,這個檢查不是必須的,FreeRTOS的作者將這個檢查放在了斷言中(configASSERT( pxTCB == pxCurrentTCB);).*/ if( pxMutex->pxMutexHolder == ( void * )xTaskGetCurrentTaskHandle() ) { /* 每當任務(wù)獲得遞歸互斥量時,隊列結(jié)構(gòu)體成員u.uxRecursiveCallCount會加1,互斥量不會使用這個變量,它用來保存遞歸次數(shù).所以,在釋放遞歸互斥量的時候要將它減1*/ ( pxMutex->u.uxRecursiveCallCount)--; /* 遞歸計數(shù)器為0? */ if( pxMutex->u.uxRecursiveCallCount == ( UBaseType_t ) 0 ) { /* 調(diào)用入隊函數(shù)釋放1個互斥量,注意阻塞時間(由宏queueMUTEX_GIVE_BLOCK_TIME定義)為0 */ ( void ) xQueueGenericSend( pxMutex, NULL,queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK ); } xReturn = pdPASS; } else { /* 如果不是本任務(wù)具有這個互斥量,則直接返回毛病碼 */ xReturn = pdFAIL; } return xReturn; } #endif /* configUSE_RECURSIVE_MUTEXES */

         這個函數(shù)是帶條件編譯的,只有將宏configUSE_RECURSIVE_MUTEXES定義為1才會編譯這個函數(shù)。

         互斥量和遞歸互斥量的最大區(qū)分在于1個遞歸互斥量可以被已獲得這個遞歸互斥量的任務(wù)重復獲得,這個遞歸調(diào)用功能是通過隊列結(jié)構(gòu)體成員u.uxRecursiveCallCount實現(xiàn)的。這個變量用于存儲遞歸調(diào)用的次數(shù),每次獲得遞歸互斥量后,這個變量加1,在釋放遞歸互斥量后,這個變量減1。只有這個變量減到0,即釋放和獲得的次數(shù)相等時,互斥量才能再次有效,使用入隊函數(shù)釋放1個遞歸互斥量。

5.獲得遞歸互斥量

         函數(shù)xSemaphoreTakeRecursive()用于獲得1個遞歸互斥量。像其它信號量1樣,xSemaphoreTakeRecursive()也是1個宏定義,它終究使用現(xiàn)有的隊列機制,實際履行的函數(shù)是xQueueTakeMutexRecursive(),這個宏定義以下所示:

#definexSemaphoreTakeRecursive( xMutex, xBlockTime ) \ xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) )

        獲得遞歸互斥量具有阻塞超時參數(shù),如果互斥量正被別的任務(wù)使用,可以阻塞設(shè)定的時間。我們重點來看函數(shù)xQueueTakeMutexRecursive()的實現(xiàn)進程。經(jīng)過整理后(去除跟蹤調(diào)試語句)的源碼以下所示:

#if ( configUSE_RECURSIVE_MUTEXES == 1 ) BaseType_txQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_txTicksToWait ) { BaseType_t xReturn; Queue_t * const pxMutex = ( Queue_t * ) xMutex; /*互斥量和遞歸互斥量要在同1個任務(wù)中獲得和釋放,遞歸互斥量可以在1個任務(wù)中屢次獲得,當?shù)?次獲得遞歸互斥量時,隊列結(jié)構(gòu)體成員指針pxMutexHolder指向獲得遞歸互斥量的任務(wù)TCB,在此獲得這個遞歸互斥量時,如果這個指針指向的TCB和當前任務(wù)TCB相同,只需要將遞歸次數(shù)計數(shù)器u.uxRecursiveCallCount加1便可,不需要再操作隊列.*/ if( pxMutex->pxMutexHolder == ( void * )xTaskGetCurrentTaskHandle() ) { ( pxMutex->u.uxRecursiveCallCount)++; xReturn = pdPASS; } else { /*調(diào)用出隊函數(shù)*/ xReturn =xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE ); /* 成功獲得遞歸互斥量后,要將遞歸次數(shù)計數(shù)器加1*/ if( xReturn != pdFAIL ) { ( pxMutex->u.uxRecursiveCallCount)++; } } return xReturn; } #endif /* configUSE_RECURSIVE_MUTEXES */

         這個函數(shù)是帶條件編譯的,只有將宏configUSE_RECURSIVE_MUTEXES定義為1才會編譯這個函數(shù)。

         程序邏輯比較簡單,如果是第1次獲得這個遞歸互斥量,直接使用出隊函數(shù),成功后將遞歸次數(shù)計數(shù)器加1;如果是第2次或更屢次獲得這個遞歸互斥量,則只需要將遞歸次數(shù)計數(shù)器加1便可。


生活不易,碼農(nóng)辛苦
如果您覺得本網(wǎng)站對您的學習有所幫助,可以手機掃描二維碼進行捐贈
程序員人生
------分隔線----------------------------
分享到:
------分隔線----------------------------
關(guān)閉
程序員人生
主站蜘蛛池模板: 成人国产精品免费观看视频 | 国产精品成人一区二区网站软件 | 久久久亚洲综合 | 免费a在线看 | 99国产精品视频免费观看 | 夜夜春影院| 色婷婷狠 | 日韩精品一区二区三区中文字幕 | 中文有码在线视频 | 欧美激情在线看 | 中文日韩 | 91小视频版在线观看www | 婷婷色综合 | 欧美在线小视频 | 亚洲天堂第一页 | 一二区视频 | 99国产精品99 | 国产成人精品三级麻豆 | 国产精品久久久久久久久久尿 | 国产理论一区二区三区 | 国产精品久久久av久久久 | 午夜色播 | 国产情侣一区二区三区 | 亚洲精品久久久久国产 | 国产少妇自拍 | 亚洲日本一区二区 | 91精品国产91久久久久久吃药 | 中文字幕在线观看第一页 | 91麻豆精品久久久久蜜臀 | 欧美淫视频 | 成人国产一区二区 | 可以免费看的av | 在线视频 中文字幕 | 亚洲欧美日韩高清 | 81精品久久久久久久婷婷 | 中文字幕亚洲一区二区三区 | 久久久精品区 | 欧美亚洲一二三 | 成人久久久久 | 欧美日韩中文字幕在线视频 | 欧美国产精品一区二区 |