用於信號量的隊列,都是只有隊列數據結構的空間,沒有隊列項存儲空間的隊列。
二值、計數、互斥、遞歸互斥,創建完成之后的內存狀態:(轉自 http://blog.csdn.net/zhzht19861011/article/details/51537234)
一、創建二值信號量
/** * semphr. h * SemaphoreHandle_t xSemaphoreCreateBinary( void ) * * Creates a new binary semaphore instance, and returns a handle by which the * new semaphore can be referenced. * * <i>Macro</i> that implements a semaphore by using the existing queue mechanism. * The queue length is 1 as this is a binary semaphore. The data size is 0 as we don't want to actually store any data -
* we just want to know if the queue is empty or full. */ #if( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) #define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH(=0), queueQUEUE_TYPE_BINARY_SEMAPHORE(類型) ) #endif
hint: QueueHandle_t xQueueGenericCreate( const UBaseType_t uxQueueLength, const UBaseType_t uxItemSize, const uint8_t ucQueueType )
只關注這個隊列是否為滿,判斷 uxMsgWaiting 即可。(只有隊列數據結構的空間,沒有隊列項存儲空間的隊列)
volatile UBaseType_t uxMessagesWaiting; /*< The number of items currently in the queue. */ item數量
二、釋放信號量(入隊)
#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME(=0), queueSEND_TO_BACK )
hint: BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition )
#define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueGiveFromISR( ( QueueHandle_t ) ( xSemaphore ), ( pxHigherPriorityTaskWoken ) )
絕對不能,用此函數Give互斥信號量! 互斥信號量涉及到優先級繼承,不能在中斷中獲取和釋放...
三、獲取信號量(出隊)
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )
hint: BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )
#define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) xQueueReceiveFromISR( ( QueueHandle_t ) ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) )
同樣的,絕對不能,用此函數Take互斥信號量! 互斥信號量涉及到優先級繼承,不能在中斷中獲取和釋放...
===========================================================
創建計數型信號量
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount ) { QueueHandle_t xHandle; configASSERT( uxMaxCount != 0 ); configASSERT( uxInitialCount <= uxMaxCount ); xHandle = xQueueGenericCreate( uxMaxCount, queueSEMAPHORE_QUEUE_ITEM_LENGTH(=0), queueQUEUE_TYPE_COUNTING_SEMAPHORE(類型) ); if( xHandle != NULL ) { ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount; 使用uxMsgWaiting計數,這里是初始化賦值。 traceCREATE_COUNTING_SEMAPHORE(); } else { traceCREATE_COUNTING_SEMAPHORE_FAILED(); } return xHandle; }
Give和Take,同上。
===========================================================
互斥信號量
優先級繼承並不能完全的消除優先級翻轉, 它只是盡可能的降低優先級翻轉帶來的影響。 【因為畢竟高優先級的任務確實是被耽擱了】
互斥信號量不能用於中斷服務函數中,原因如下:
1. 互斥信號量有優先級繼承的機制,所以只能用在任務中,不能用於中斷服務函數。
2. 中斷服務函數中不能因為要等待互斥信號量而設置阻塞時間進入阻塞態。 xSemaphoreTake( xSemaphore, xBlockTime )
一、創建互斥信號量
SemaphoreHandle_t xSemaphoreCreateMutex( void )
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
#if( ( configUSE_MUTEXES == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) ) QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType ) { Queue_t *pxNewQueue; const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0; 隊列長度1,item長度0
pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType ); 類型應該是queueQUEUE_TYPE_MUTEX prvInitialiseMutex( pxNewQueue ); return pxNewQueue; } #endif /* configUSE_MUTEXES */
static void prvInitialiseMutex( Queue_t *pxNewQueue )
{
if( pxNewQueue != NULL ) { /* The queue create function will set all the queue structure members correctly for a generic queue, but this function is creating a mutex. Overwrite those members that need to be set differently - in particular the information required for priority inheritance. */
隊列創建的時候會初始化隊列,但這里需要重新賦值,尤其和優先級繼承相關的。 pxNewQueue->pxMutexHolder = NULL; pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; /* In case this is a recursive mutex. */ pxNewQueue->u.uxRecursiveCallCount = 0; 專門用於,遞歸互斥信號量(跟u.readFrom指針占一個空間) traceCREATE_MUTEX( pxNewQueue ); /* Start with the semaphore in the expected state. */ ( void ) xQueueGenericSend( pxNewQueue, NULL, ( TickType_t ) 0U, queueSEND_TO_BACK ); 互斥資源一定是存在的,所以創建互斥量時會先釋放一個互斥量,表示這個資源可以使用。 } else { traceCREATE_MUTEX_FAILED(); }
}
這兩個宏專門為互斥信號量准備:
#define pxMutexHolder pcTail
#define uxQueueType pcHead
#define queueQUEUE_IS_MUTEX NULL
當用於互斥信號量的時候將
pcHead(uxQueueType) 指向 NULL,
pcTail(pxMutexHolder) 指向 TCB,擁有互斥信號量的任務的任務控制塊。
二、釋放互斥信號量
釋放互斥信號量的時候和二值信號量、計數型信號量一樣,都是用的函數 xSemaphoreGive()(實際上完成信號量釋放的是函數 xQueueGenericSend())。
使用函數 xSemaphoreGive()釋放信號量最重要的一步就是將uxMessagesWaiting加一, 和優先級繼承,這兩個都是在函數 prvCopyDataToQueue()中完成的。
QueueGenericSend 調用 CopyDataToQueue.
1 static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition )
2 { 3 BaseType_t xReturn = pdFALSE; 4 UBaseType_t uxMessagesWaiting; 5 6 /* This function is called from a critical section. */ 7 8 uxMessagesWaiting = pxQueue->uxMessagesWaiting; 9 10 if( pxQueue->uxItemSize == ( UBaseType_t ) 0 ) 隊列item長度為0,專為信號量設計。 11 { 12 #if ( configUSE_MUTEXES == 1 ) 互斥信號量 13 { 14 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) 15 { 16 /* The mutex is no longer being held. */ 17 xReturn = xTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder ); 處理優先級繼承問題! 18 pxQueue->pxMutexHolder = NULL; 互斥量釋放后,就不屬於任何任務了,所以Holder指向NULL. 19 } 20 else 21 { 22 mtCOVERAGE_TEST_MARKER(); 23 } 24 } 25 #endif /* configUSE_MUTEXES */ 26 } 27 else if( xPosition == queueSEND_TO_BACK ) 加入到隊列最后 28 { 29 ( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 !e418 */ 30 pxQueue->pcWriteTo += pxQueue->uxItemSize; 31 if( pxQueue->pcWriteTo >= pxQueue->pcTail ) /*lint !e946 */ 32 { 33 pxQueue->pcWriteTo = pxQueue->pcHead; 34 } 35 else 36 { 37 mtCOVERAGE_TEST_MARKER(); 38 } 39 } 40 else 加入到隊列最前 41 { 42 ( void ) memcpy( ( void * ) pxQueue->u.pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize ); /*lint !e961 */ 43 pxQueue->u.pcReadFrom -= pxQueue->uxItemSize; 44 if( pxQueue->u.pcReadFrom < pxQueue->pcHead ) /*lint !e946 */ 45 { 46 pxQueue->u.pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize ); 47 } 48 else 49 { 50 mtCOVERAGE_TEST_MARKER(); 51 } 52 53 if( xPosition == queueOVERWRITE ) 覆蓋寫入,統計item數量值自減。 54 { 55 if( uxMessagesWaiting > ( UBaseType_t ) 0 ) 56 { 57 /* An item is not being added but overwritten, so subtract 58 one from the recorded number of items in the queue so when 59 one is added again below the number of recorded items remains 60 correct. */ 61 --uxMessagesWaiting; 62 } 63 else 64 { 65 mtCOVERAGE_TEST_MARKER(); 66 } 67 } 68 else 69 { 70 mtCOVERAGE_TEST_MARKER(); 71 } 72 } 73 74 pxQueue->uxMessagesWaiting = uxMessagesWaiting + 1; 重點變量 75 76 return xReturn; 77 }
1 #if ( configUSE_MUTEXES == 1 ) 2 3 BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder ) 4 { 5 TCB_t * const pxTCB = ( TCB_t * ) pxMutexHolder; 6 BaseType_t xReturn = pdFALSE; 7 8 if( pxMutexHolder != NULL ) Holder表示擁有此互斥量的TCB,先判斷其是否被其他任務獲取。 9 { 10 /* A task can only have an inherited priority if it holds the mutex. 11 If the mutex is held by a task then it cannot be given from an 12 interrupt, and if a mutex is given by the holding task then it must 13 be the running state task. */ 14 configASSERT( pxTCB == pxCurrentTCB ); 讀上邊英文 15 16 configASSERT( pxTCB->uxMutexesHeld ); uxMutexesHeld保存當前任務獲取到的互斥量的個數,可能獲取多個互斥量 17 ( pxTCB->uxMutexesHeld )--; 18 19 /* Has the holder of the mutex inherited the priority of another 20 task? */ 21 if( pxTCB->uxPriority != pxTCB->uxBasePriority ) 是否存在優先級繼承,如果存在,那么任務當下的Prio和任務的BasePrio肯定不同! 22 { 23 /* Only disinherit if no other mutexes are held. */ 當前任務只獲取了一個互斥量 24 if( pxTCB->uxMutexesHeld == ( UBaseType_t ) 0 ) 25 { 26 /* A task can only have an inherited priority if it holds 27 the mutex. If the mutex is held by a task then it cannot be 28 given from an interrupt, and if a mutex is given by the 29 holding task then it must be the running state task. Remove 30 the holding task from the ready list. */
判斷當前釋放的是不是任務所獲取的最后一個互斥量,優先級繼承的處理,必須是在“釋放最后一個互斥量時”。
31 if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
32 {
33 taskRESET_READY_PRIORITY( pxTCB->uxPriority ); 如果繼承來的這個優先級,沒有其他就緒任務,清除這個優先級的就緒態(TopReadyPrio變量)
34 }
35 else
36 {
37 mtCOVERAGE_TEST_MARKER();
38 }
40 /* Disinherit the priority before adding the task into the 41 new ready list. */ 使用新優先級(BasePrio),將任務加入到就緒列表。 42 traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority ); 43 pxTCB->uxPriority = pxTCB->uxBasePriority; 重新設置為BasePrio. 44 45 /* Reset the event list item value. 重置事件列表項的值 It cannot be in use for 46 any other purpose if this task is running, and it must be 47 running to give back歸還 the mutex. */ 這個列表的排放順序是,跟優先級的數值反着來的哦!【優先級數越小越低】 48 listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); /*lint !e961 */ 49 prvAddTaskToReadyList( pxTCB ); 優先級恢復后,任務加到BasePrio的就緒表. 50 51 /* Return true to indicate that a context switch is required. 52 This is only actually required in the corner case whereby 53 multiple mutexes were held and the mutexes were given back 54 in an order different to that in which they were taken. 55 If a context switch did not occur when the first mutex was 56 returned, even if a task was waiting on it,/ then那么 a context 57 switch should必須 occur when the last mutex is returned whether 58 a task is waiting on it or not. */ 59 xReturn = pdTRUE; //return ture表示需要任務切換 60 } 61 else 62 { 63 mtCOVERAGE_TEST_MARKER(); 64 } 65 } 66 else 67 { 68 mtCOVERAGE_TEST_MARKER(); 69 } 70 } 71 else 72 { 73 mtCOVERAGE_TEST_MARKER(); 74 } 75 76 return xReturn; 77 } 78 79 #endif /* configUSE_MUTEXES */
簡化為兩種情況:
第一,如果隊列未滿,除了隊列結構體成員uxMessageWaiting加1外,還要判斷獲取互斥量的任務是否有優先級繼承,
如果有的話,還要將任務的優先級恢復到原始值,操作任務狀態所在的隊列等。
當然,恢復到原來值也是有條件的,就是該任務必須在沒有使用其它互斥量的情況下,才能將繼承的優先級恢復到原始值。
然后數據入隊成功,判斷是否有阻塞的任務,有的話解除阻塞,最后返回成功信息(pdPASS);
第二,如果如果隊列滿,返回錯誤代碼(err_QUEUE_FULL),表示隊列滿。
三、獲取互斥信號量
獲取互斥量的函數同獲取二值信號量和計數型信號量的函數相同,都是 xSemaphoreTake( xSemaphore, xBlockTime )(實際執行信號量獲取的函數是 xQueueGenericReceive())。
獲取互斥信號量的過程也需要處理優先級繼承的問題。
1 BaseType_t xQueueGenericReceive( QueueHandle_t xQueue, void * const pvBuffer, TickType_t xTicksToWait, const BaseType_t xJustPeeking )
2 { 3 BaseType_t xEntryTimeSet = pdFALSE; 4 TimeOut_t xTimeOut; 5 int8_t *pcOriginalReadPosition; 6 Queue_t * const pxQueue = ( Queue_t * ) xQueue; 7 8 configASSERT( pxQueue ); 9 configASSERT( !( ( pvBuffer == NULL ) && ( pxQueue->uxItemSize != ( UBaseType_t ) 0U ) ) ); 10 #if ( ( INCLUDE_xTaskGetSchedulerState == 1 ) || ( configUSE_TIMERS == 1 ) ) 11 { 12 configASSERT( !( ( xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED ) && ( xTicksToWait != 0 ) ) ); 13 } 14 #endif 15 16 /* This function relaxes the coding standard somewhat to allow return 17 statements within the function itself. This is done in the interest 18 of execution time efficiency. */ 19 20 for( ;; ) 21 { 22 taskENTER_CRITICAL(); 23 { 24 const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting; 25 26 /* Is there data in the queue now? To be running the calling task 27 must be the highest priority task wanting to access the queue. */ 28 if( uxMessagesWaiting > ( UBaseType_t ) 0 ) 判斷隊列是否有消息 29 { 30 /* Remember the read position in case the queue is only being 31 peeked. */ 32 pcOriginalReadPosition = pxQueue->u.pcReadFrom; 33 34 prvCopyDataFromQueue( pxQueue, pvBuffer ); 35 36 if( xJustPeeking == pdFALSE ) 【非peek讀取】 37 { 38 traceQUEUE_RECEIVE( pxQueue ); 39 40 /* Actually removing data, not just peeking. */ 41 pxQueue->uxMessagesWaiting = uxMessagesWaiting - 1; 42 43 #if ( configUSE_MUTEXES == 1 ) 44 { 45 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) 隊列類型是互斥量 46 { 47 /* Record the information required to implement 48 priority inheritance should it become necessary. */ 49 pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); /*lint !e961 */ holder是當前任務的TCB,
函數TaskIncrementMutexHeldCnt只是把MutexHeld加一,表示任務獲取了一個互斥量,這個函數返回當前任務的TCB
50 } 51 else 52 { 53 mtCOVERAGE_TEST_MARKER(); 54 } 55 } 56 #endif /* configUSE_MUTEXES */ 57 58 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE ) 出隊成功,判斷是否"有任務入隊阻塞" 59 { 60 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE ) 61 { 62 queueYIELD_IF_USING_PREEMPTION(); 解除阻塞任務的優先級比當前任務高,需要進行任務切換。 63 } 64 else 65 { 66 mtCOVERAGE_TEST_MARKER(); 67 } 68 } 69 else 70 { 71 mtCOVERAGE_TEST_MARKER(); 72 } 73 } 74 else 【peek讀取】 75 { 76 traceQUEUE_PEEK( pxQueue ); 77 78 /* The data is not being removed, so reset the read 79 pointer. */ 80 pxQueue->u.pcReadFrom = pcOriginalReadPosition; 重置讀指針,剛剛出隊的消息仍然有效。 81 82 /* The data is being left in the queue, so see if there are 83 any other tasks waiting for the data. */ 84 if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE ) 消息仍然有效,判斷是否有任務因為出隊阻塞 85 { 86 if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToReceive ) ) != pdFALSE ) 87 { 88 /* The task waiting has a higher priority than this task. */ 89 queueYIELD_IF_USING_PREEMPTION(); 同樣的解除阻塞的prio高於當前任務,則切換任務。 90 } 91 else 92 { 93 mtCOVERAGE_TEST_MARKER(); 94 } 95 } 96 else 97 { 98 mtCOVERAGE_TEST_MARKER(); 99 } 100 } 101 102 taskEXIT_CRITICAL(); 103 return pdPASS; 104 } 105 else 【隊列為空】 106 { 107 if( xTicksToWait == ( TickType_t ) 0 ) 阻塞時間0,直接返回 errQUEUE_EMPTY 108 { 109 /* The queue was empty and no block time is specified (or 110 the block time has expired) so leave now. */ 111 taskEXIT_CRITICAL(); 112 traceQUEUE_RECEIVE_FAILED( pxQueue ); 113 return errQUEUE_EMPTY; 114 } 115 else if( xEntryTimeSet == pdFALSE ) 阻塞時間不為零,初始化時間狀態結構體 116 { 117 /* The queue was empty and a block time was specified so 118 configure the timeout structure. */ 119 vTaskSetTimeOutState( &xTimeOut ); 120 xEntryTimeSet = pdTRUE; 121 } 122 else 123 { 124 /* Entry time was already set. */ 125 mtCOVERAGE_TEST_MARKER(); 126 } 127 } 128 } 129 taskEXIT_CRITICAL(); 130 131 /* Interrupts and other tasks can send to and receive from the queue 132 now the critical section has been exited. */ 133 134 vTaskSuspendAll(); 135 prvLockQueue( pxQueue ); 136 137 /* Update the timeout state to see if it has expired yet. */ 更新時間狀態結構體,並且檢查超時是否發生。 138 if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE ) 超時沒有發生 139 { 140 if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) 【隊列為空】 141 { 142 traceBLOCKING_ON_QUEUE_RECEIVE( pxQueue ); 143 144 #if ( configUSE_MUTEXES == 1 ) 145 { 146 if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) 是互斥量 147 { 148 taskENTER_CRITICAL(); 149 { 150 vTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); 調用函數處理優先級繼承問題。
執行到這里說明互斥量正在被其他任務占用。
TaskPrioInherit函數與TaskPrioDisinherit()過程相反:
此函數會判斷當前任務的Prio是否比正擁有互斥量的任務Prio高,如果高,就會把擁有互斥量的那個低Prio任務調整為與當前任務相同的優先級。 151 } 152 taskEXIT_CRITICAL(); 153 } 154 else 155 { 156 mtCOVERAGE_TEST_MARKER(); 157 } 158 } 159 #endif 160 161 vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait ); 將任務添加到WaitToRcv列表。 162 prvUnlockQueue( pxQueue ); 163 if( xTaskResumeAll() == pdFALSE ) 164 { 165 portYIELD_WITHIN_API(); 166 } 167 else 168 { 169 mtCOVERAGE_TEST_MARKER(); 170 } 171 } 172 else 【隊列不為空】 173 { 174 /* Try again. */ 重試一次 175 prvUnlockQueue( pxQueue ); 176 ( void ) xTaskResumeAll(); 177 } 178 } 179 else 【超時了】 180 { 181 prvUnlockQueue( pxQueue ); 182 ( void ) xTaskResumeAll(); 183 184 if( prvIsQueueEmpty( pxQueue ) != pdFALSE ) 隊列還是空的 185 { 186 traceQUEUE_RECEIVE_FAILED( pxQueue ); 187 return errQUEUE_EMPTY; 返回隊列空! 188 } 189 else 190 { 191 mtCOVERAGE_TEST_MARKER(); 192 } 193 } 194 } 195 }
互斥信號量,任務中必須具有take和give成對出現。(解決優先級繼承)
===========================================================
一、遞歸互斥量
已經獲取了遞歸互斥信號量的任務可以再次獲取這個遞歸互斥信號量,而且次數不限!
一個任務使用函數 xSemaphoreTakeRecursive()成功的獲取了多少次遞歸互斥信號量,
就得使用函數 xSemaphoreGiveRecursive()釋放多少次。
遞歸互斥信號量也有優先級繼承的機制,所以當任務使用完遞歸互斥信號量以后一定要釋放。
同互斥信號量一樣,遞歸互斥信號量不能用在中斷服務函數中。
1. 互斥信號量有優先級繼承的機制,所以只能用在任務中,不能用於中斷服務函數。
2. 中斷服務函數中不能因為要等待互斥信號量而設置阻塞時間進入阻塞態。 xSemaphoreTakeRecursive( xMutex, xBlockTime )
一、創建
SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void ) #define xSemaphoreCreateRecursiveMutex() xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX ) 創建過程和互斥量一樣,類型選擇為 queueQUEUE_TYPE_RECURSIVE_MUTEX。
二、釋放
#define xSemaphoreGiveRecursive( xMutex ) xQueueGiveMutexRecursive( ( xMutex ) ) #if ( configUSE_RECURSIVE_MUTEXES == 1 ) BaseType_t xQueueGiveMutexRecursive( QueueHandle_t xMutex ) { BaseType_t xReturn; Queue_t * const pxMutex = ( Queue_t * ) xMutex; configASSERT( pxMutex ); /* If this is the task that holds the mutex then pxMutexHolder will not change outside of this task. If this task does not hold the mutex then pxMutexHolder can never coincidentally equal the tasks handle, and as this is the only condition we are interested in it does not matter if pxMutexHolder is accessed simultaneously by another task. Therefore no mutual exclusion is required to test the pxMutexHolder variable. */
檢查遞歸互斥量是不是被當前任務獲取的,要釋放遞歸互斥量的任務肯定是當前運行的任務。
和互斥量一樣,Take和Give要在同一個任務中完成!
如果當前正在運行的任務不是遞歸互斥量的擁有者,就不能釋放! if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 */ { traceGIVE_MUTEX_RECURSIVE( pxMutex ); /* uxRecursiveCallCount cannot be zero if pxMutexHolder is equal to the task handle, therefore no underflow check is required. Also, uxRecursiveCallCount is only modified by the mutex holder, and as there can only be one, no mutual exclusion is required to modify the uxRecursiveCallCount member. */
CallCnt記錄被Take的次數,
多次Take多次Give的實現:
Give的時候只在最后一次調用xQueueGenericSend(),其他時候只是簡單的將CallCnt減一。 ( pxMutex->u.uxRecursiveCallCount )--; /* Has the recursive call count unwound to 0? */ if( pxMutex->u.uxRecursiveCallCount == ( UBaseType_t ) 0 ) 是最后一次釋放了。 { /* Return the mutex. This will automatically unblock any other task that might be waiting to access the mutex. */ ( void ) xQueueGenericSend( pxMutex, NULL,
queueMUTEX_GIVE_BLOCK_TIME(=0), queueSEND_TO_BACK ); } else { mtCOVERAGE_TEST_MARKER(); } xReturn = pdPASS; Give成功 } else { /* The mutex cannot be given because the calling task is not the holder. */ xReturn = pdFAIL; Give失敗 traceGIVE_MUTEX_RECURSIVE_FAILED( pxMutex ); } return xReturn; } #endif /* configUSE_RECURSIVE_MUTEXES */
三、獲取
#define xSemaphoreTakeRecursive( xMutex, xBlockTime ) xQueueTakeMutexRecursive( ( xMutex ), ( xBlockTime ) ) #if ( configUSE_RECURSIVE_MUTEXES == 1 ) BaseType_t xQueueTakeMutexRecursive( QueueHandle_t xMutex, TickType_t xTicksToWait ) { BaseType_t xReturn; Queue_t * const pxMutex = ( Queue_t * ) xMutex; configASSERT( pxMutex ); /* Comments regarding mutual exclusion as per those within xQueueGiveMutexRecursive(). */ traceTAKE_MUTEX_RECURSIVE( pxMutex );
判斷當前要Take遞歸量的任務是不是已經是Hodler,通過這一步判斷當前任務是第一次Take還是重復Take。 if( pxMutex->pxMutexHolder == ( void * ) xTaskGetCurrentTaskHandle() ) /*lint !e961 */ { ( pxMutex->u.uxRecursiveCallCount )++; 本次是重復Take,就簡單的CallCnt加一 xReturn = pdPASS; 返回Take成功 } else { xReturn = xQueueGenericReceive( pxMutex, NULL, xTicksToWait, pdFALSE ); 第一次Take的話,完成真正的Take過程! /* pdPASS will only be returned if the mutex was successfully obtained. The calling task may have entered the Blocked state before reaching here. */ if( xReturn != pdFAIL ) { ( pxMutex->u.uxRecursiveCallCount )++; 第一次Take成功后,CallCnt加一 } else { traceTAKE_MUTEX_RECURSIVE_FAILED( pxMutex ); } } return xReturn; } #endif /* configUSE_RECURSIVE_MUTEXES */
任務獲取了三次遞歸互斥信號量,所以就得釋放三次!
遞歸互斥信號量釋放完成后,可以被其他任務獲取。
這兩個API不能給互斥量用(只能二值、計數型):
xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken )
xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken )
這兩個API通用(二值、計數型、互斥):
xSemaphoreGive( xSemaphore )
xSemaphoreTake( xSemaphore, xBlockTime )
專門給遞歸量用:
xSemaphoreGiveRecursive( xMutex )
xSemaphoreTakeRecursive( xMutex, xBlockTime )
留白