FreeRTOS互斥锁
信號(hào)量API函數(shù)實(shí)際上都是宏,它使用現(xiàn)有的隊(duì)列機(jī)制。這些宏定義在semphr.h文件中。如果使用信號(hào)量或者互斥量,需要包含semphr.h頭文件。
信號(hào)量包括二值信號(hào)量、計(jì)數(shù)信號(hào)量、互斥信號(hào)量和遞歸互斥信號(hào)量。和普通隊(duì)列比起來(lái),信號(hào)量雖然沒(méi)有隊(duì)列項(xiàng)實(shí)體,但是信號(hào)量值等同于隊(duì)列項(xiàng)個(gè)數(shù)。
?
?
互斥鎖和遞歸互斥鎖:互斥鎖是用來(lái)保證共享數(shù)據(jù)操作的完整性,同時(shí)只能有一個(gè)任務(wù)訪問(wèn)共享數(shù)據(jù)。遞歸互斥鎖和普通互斥鎖比起來(lái),同一個(gè)任務(wù)可以多次獲取遞歸互斥鎖,在釋放同等次數(shù)之后才能解鎖。
?
?
在分析互斥鎖之前,先搞清楚兩個(gè)概念,優(yōu)先級(jí)反轉(zhuǎn)和優(yōu)先級(jí)繼承
優(yōu)先級(jí)反轉(zhuǎn):互斥鎖被低優(yōu)先級(jí)的任務(wù)持有,高優(yōu)先級(jí)任務(wù)等待解鎖。這時(shí)中等優(yōu)先級(jí)任務(wù)一直運(yùn)行,這導(dǎo)致高優(yōu)先級(jí)任務(wù)在等待低優(yōu)先級(jí)任務(wù),而低優(yōu)先級(jí)任務(wù)無(wú)法執(zhí)行。這種高優(yōu)先級(jí)等待中優(yōu)先級(jí)的情況,叫做優(yōu)先級(jí)反轉(zhuǎn)。
優(yōu)先級(jí)繼承:為了解決優(yōu)先級(jí)反轉(zhuǎn)而提出優(yōu)化機(jī)制,讓低優(yōu)先級(jí)任務(wù)臨時(shí)繼承高優(yōu)先級(jí)任務(wù)的優(yōu)先級(jí)。在低優(yōu)先級(jí)釋放互斥鎖之后,還要恢復(fù)原來(lái)的優(yōu)先級(jí)。
?
?
先看一下任務(wù)TCB
因?yàn)閮?yōu)先級(jí)繼承機(jī)制,在互斥鎖釋放后需要恢復(fù)優(yōu)先級(jí),uxBasePriority在優(yōu)先級(jí)繼承期間被用來(lái)保存任務(wù)優(yōu)先級(jí)
uxMutexesHeld表示任務(wù)持有了多少個(gè)互斥鎖
/* 任務(wù)TCB */ typedef struct tskTaskControlBlock {volatile StackType_t *pxTopOfStack; /* 棧頂?shù)刂?*/......ListItem_t xStateListItem; /* 狀態(tài)列表項(xiàng):運(yùn)行、就緒、掛起、阻塞 */ListItem_t xEventListItem; /* 事件列表項(xiàng) */UBaseType_t uxPriority; /* 優(yōu)先級(jí) */StackType_t *pxStack; /* 棧指針 */char pcTaskName[configMAX_TASK_NAME_LEN]; /* 任務(wù)名 */......#if (configUSE_MUTEXES == 1)UBaseType_t uxBasePriority; /* 任務(wù)基礎(chǔ)優(yōu)先級(jí) */UBaseType_t uxMutexesHeld; /* 互斥鎖持有數(shù)量 */ #endif...... }tskTCB; typedef tskTCB TCB_t;?
?
創(chuàng)建互斥鎖
?互斥鎖實(shí)際上是調(diào)用了隊(duì)列的創(chuàng)建函數(shù),創(chuàng)建好之后調(diào)用prvInitialiseMutex來(lái)初始化一些互斥鎖特有的變量
#define xSemaphoreCreateMutex() xQueueCreateMutex(queueQUEUE_TYPE_MUTEX) /* 創(chuàng)建互斥鎖 */ QueueHandle_t xQueueCreateMutex(const uint8_t ucQueueType) {QueueHandle_t xNewQueue;const UBaseType_t uxMutexLength = (UBaseType_t)1, uxMutexSize = (UBaseType_t)0;/* 創(chuàng)建互斥鎖隊(duì)列 */xNewQueue = xQueueGenericCreate(uxMutexLength, uxMutexSize, ucQueueType);/* 初始化互斥鎖隊(duì)列 */prvInitialiseMutex((Queue_t *)xNewQueue);return xNewQueue; }prvInitialiseMutex函數(shù),將互斥鎖初始化為沒(méi)有被任何任務(wù)持有,并且處于解鎖狀態(tài)(隊(duì)列中有一個(gè)隊(duì)列項(xiàng))
/* 初始化互斥鎖 */ static void prvInitialiseMutex(Queue_t *pxNewQueue) {if(pxNewQueue != NULL){/* 初始化互斥鎖的持有者為空 */pxNewQueue->u.xSemaphore.xMutexHolder = NULL;/* 初始化隊(duì)列類型為互斥鎖 */pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX;/* 初始化遞歸次數(shù)為0 */pxNewQueue->u.xSemaphore.uxRecursiveCallCount = 0;traceCREATE_MUTEX(pxNewQueue);/* 初始化互斥鎖為解鎖狀態(tài)(向隊(duì)列中發(fā)送一個(gè)隊(duì)列項(xiàng)) */(void)xQueueGenericSend(pxNewQueue, NULL, (TickType_t)0U, queueSEND_TO_BACK);}else{traceCREATE_MUTEX_FAILED();} }?
?
獲取互斥鎖
互斥鎖也叫互斥信號(hào)量,獲取互斥鎖和獲取信號(hào)量使用同一個(gè)函數(shù)
和普通信號(hào)量不同的是:
1.獲取成功時(shí),將互斥鎖持有者設(shè)為當(dāng)前任務(wù),當(dāng)前任務(wù)持有互斥鎖數(shù)量加一
2.因互斥鎖被其它任務(wù)持有而阻塞時(shí),為了防止優(yōu)先級(jí)反轉(zhuǎn)現(xiàn)象,進(jìn)行優(yōu)先級(jí)繼承處理
3.因互斥鎖被其它任務(wù)持有而阻塞,超時(shí)之后,因?yàn)榭赡苓M(jìn)行了優(yōu)先級(jí)繼承,剝奪原先繼承的優(yōu)先級(jí)(剝不剝奪看優(yōu)先級(jí)是否繼承自該任務(wù))
從源代碼看,調(diào)用xTaskPriorityInherit函數(shù)來(lái)進(jìn)行優(yōu)先級(jí)繼承;在超時(shí)之后,使用prvGetDisinheritPriorityAfterTimeout和vTaskPriorityDisinheritAfterTimeout函數(shù)來(lái)恢復(fù)優(yōu)先級(jí)
#define xSemaphoreTake(xSemaphore, xBlockTime) xQueueSemaphoreTake((xSemaphore), (xBlockTime)) /* 獲取信號(hào)量值 */ BaseType_t xQueueSemaphoreTake(QueueHandle_t xQueue, TickType_t xTicksToWait) {BaseType_t xEntryTimeSet = pdFALSE;TimeOut_t xTimeOut;Queue_t *const pxQueue = xQueue;#if (configUSE_MUTEXES == 1)BaseType_t xInheritanceOccurred = pdFALSE; #endifconfigASSERT((pxQueue));configASSERT(pxQueue->uxItemSize == 0);#if ((INCLUDE_xTaskGetSchedulerState == 1) || (configUSE_TIMERS == 1)){configASSERT(!((xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) && (xTicksToWait != 0)));}#endiffor(;;){/* 進(jìn)入臨界區(qū) */taskENTER_CRITICAL();{/* 信號(hào)量計(jì)數(shù) */const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting;/* 信號(hào)量值大于0 */if(uxSemaphoreCount > (UBaseType_t)0){traceQUEUE_RECEIVE(pxQueue);/* 信號(hào)量值減一 */pxQueue->uxMessagesWaiting = uxSemaphoreCount - (UBaseType_t)1;#if (configUSE_MUTEXES == 1){/* 隊(duì)列類型是互斥鎖 */if(pxQueue->uxQueueType == queueQUEUE_IS_MUTEX){/* 互斥鎖的持有者設(shè)為當(dāng)前任務(wù),當(dāng)前任務(wù)持有鎖的數(shù)量加一 */pxQueue->u.xSemaphore.xMutexHolder = pvTaskIncrementMutexHeldCount();}else{mtCOVERAGE_TEST_MARKER();}}#endif/* 等待釋放信號(hào)量而阻塞的任務(wù)列表不為空 */if(listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToSend)) == pdFALSE){/* 將任務(wù)從釋放信號(hào)量而阻塞的任務(wù)列表中移除,任務(wù)優(yōu)先級(jí)大于當(dāng)前任務(wù)優(yōu)先級(jí) */if(xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToSend)) != pdFALSE){/* 請(qǐng)求切換任務(wù) */queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}/* 退出臨界區(qū) */taskEXIT_CRITICAL();/* 成功 */return pdPASS;}/* 信號(hào)量值為0 */else{/* 等待時(shí)間為0 */if(xTicksToWait == (TickType_t)0){#if (configUSE_MUTEXES == 1){configASSERT(xInheritanceOccurred == pdFALSE);}#endif/* 退出臨界區(qū) */taskEXIT_CRITICAL();traceQUEUE_RECEIVE_FAILED(pxQueue);/* 返回隊(duì)列為空錯(cuò)誤 */return errQUEUE_EMPTY;}/* 沒(méi)有記錄過(guò)當(dāng)前節(jié)拍狀態(tài) */else if(xEntryTimeSet == pdFALSE){/* 記錄當(dāng)前節(jié)拍狀態(tài) */vTaskInternalSetTimeOutState(&xTimeOut);/* 已經(jīng)記錄過(guò)當(dāng)前節(jié)拍狀態(tài) */xEntryTimeSet = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}}/* 退出臨界區(qū) */taskEXIT_CRITICAL();/* 掛起調(diào)度器 */vTaskSuspendAll();/* 鎖定隊(duì)列 */prvLockQueue(pxQueue);/* 檢查是否超時(shí),沒(méi)有超時(shí) */if(xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE){/* 檢查信號(hào)量值是否為0,為0 */if(prvIsQueueEmpty(pxQueue) != pdFALSE){traceBLOCKING_ON_QUEUE_RECEIVE(pxQueue);#if (configUSE_MUTEXES == 1){/* 隊(duì)列類型為互斥鎖 */if(pxQueue->uxQueueType == queueQUEUE_IS_MUTEX){/* 進(jìn)入臨界區(qū) */taskENTER_CRITICAL();{/* 任務(wù)優(yōu)先級(jí)繼承,返回值是否繼承優(yōu)先級(jí) */xInheritanceOccurred = xTaskPriorityInherit(pxQueue->u.xSemaphore.xMutexHolder);}/* 退出臨界區(qū) */taskEXIT_CRITICAL();}else{mtCOVERAGE_TEST_MARKER();}}#endif/* 將任務(wù)插入等待獲取信號(hào)量而阻塞的任務(wù)列表中 */vTaskPlaceOnEventList(&(pxQueue->xTasksWaitingToReceive), xTicksToWait);/* 解鎖隊(duì)列 */prvUnlockQueue(pxQueue);/* 解除調(diào)度器掛起,沒(méi)有切換過(guò)任務(wù) */if(xTaskResumeAll() == pdFALSE){/* 請(qǐng)求切換任務(wù) */portYIELD_WITHIN_API();}else{mtCOVERAGE_TEST_MARKER();}}/* 隊(duì)列不為空,while下一個(gè)循環(huán)時(shí)取走隊(duì)列項(xiàng) */else{/* 解鎖隊(duì)列 */prvUnlockQueue(pxQueue);/* 解除調(diào)度器掛起 */(void)xTaskResumeAll();}}/* 已經(jīng)超時(shí)或者超時(shí)之后 */else{/* 解鎖隊(duì)列 */prvUnlockQueue(pxQueue);/* 解除調(diào)度器掛起 */(void)xTaskResumeAll();/* 檢查隊(duì)列是否為空,為空 */if(prvIsQueueEmpty(pxQueue) != pdFALSE){#if (configUSE_MUTEXES == 1){/* 繼承了優(yōu)先級(jí) */if(xInheritanceOccurred != pdFALSE){/* 進(jìn)入臨界區(qū) */taskENTER_CRITICAL();{UBaseType_t uxHighestWaitingPriority;/* 獲取剩下所有等待互斥鎖任務(wù)的最高優(yōu)先級(jí) */uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout(pxQueue);/* 超時(shí)之后剝奪繼承優(yōu)先級(jí) */vTaskPriorityDisinheritAfterTimeout(pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority);}/* 退出臨界區(qū) */taskEXIT_CRITICAL();}}#endiftraceQUEUE_RECEIVE_FAILED(pxQueue);/* 返回隊(duì)列為空錯(cuò)誤 */return errQUEUE_EMPTY;}/* 隊(duì)列不為空,while下一個(gè)循環(huán)時(shí)取走隊(duì)列項(xiàng) */else{mtCOVERAGE_TEST_MARKER();}}} }?
?
釋放互斥鎖
從源代碼來(lái)看,看不出和普通信號(hào)量處理有什么區(qū)別。
但是,因?yàn)榛コ怄i可能存在優(yōu)先級(jí)繼承的問(wèn)題,因此釋放互斥鎖時(shí)肯定需要恢復(fù)優(yōu)先級(jí)。
事實(shí)上,恢復(fù)優(yōu)先級(jí)在prvCopyDataToQueue函數(shù)中進(jìn)行。
#define xSemaphoreGive(xSemaphore) xQueueGenericSend((QueueHandle_t)(xSemaphore), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK) /* 發(fā)送隊(duì)列項(xiàng) */ BaseType_t xQueueGenericSend(QueueHandle_t xQueue, const void *const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition) {BaseType_t xEntryTimeSet = pdFALSE, xYieldRequired;TimeOut_t xTimeOut;Queue_t *const pxQueue = xQueue;configASSERT(pxQueue);configASSERT(!((pvItemToQueue == NULL) && (pxQueue->uxItemSize != (UBaseType_t)0U)));configASSERT(!((xCopyPosition == queueOVERWRITE) && (pxQueue->uxLength != 1)));#if ((INCLUDE_xTaskGetSchedulerState == 1) || (configUSE_TIMERS == 1)){configASSERT(!((xTaskGetSchedulerState() == taskSCHEDULER_SUSPENDED) && (xTicksToWait != 0)));}#endiffor(;;){/* 進(jìn)入臨界區(qū) */taskENTER_CRITICAL();{/* 目前已插入隊(duì)列項(xiàng)數(shù)小于最大可插入隊(duì)列數(shù)或者覆蓋型插入 */if((pxQueue->uxMessagesWaiting < pxQueue->uxLength) || (xCopyPosition == queueOVERWRITE)){traceQUEUE_SEND(pxQueue);#if (configUSE_QUEUE_SETS == 1){UBaseType_t uxPreviousMessagesWaiting = pxQueue->uxMessagesWaiting;xYieldRequired = prvCopyDataToQueue(pxQueue, pvItemToQueue, xCopyPosition);if(pxQueue->pxQueueSetContainer != NULL){if((xCopyPosition == queueOVERWRITE) && (uxPreviousMessagesWaiting != (UBaseType_t)0)){mtCOVERAGE_TEST_MARKER();}else if(prvNotifyQueueSetContainer(pxQueue, xCopyPosition) != pdFALSE){queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}else{if(listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive)) == pdFALSE){if(xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE){queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}else if(xYieldRequired != pdFALSE){queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}}#else{/* 根據(jù)不同的入隊(duì)方式,將隊(duì)列項(xiàng)數(shù)據(jù)拷貝到隊(duì)列中 */xYieldRequired = prvCopyDataToQueue(pxQueue, pvItemToQueue, xCopyPosition);/* 等待接收隊(duì)列項(xiàng)而阻塞的任務(wù)列表不為空 */if(listLIST_IS_EMPTY(&(pxQueue->xTasksWaitingToReceive)) == pdFALSE){/* 將任務(wù)從事件列表中移除一個(gè)任務(wù),并掛接到就緒列表 */if(xTaskRemoveFromEventList(&(pxQueue->xTasksWaitingToReceive)) != pdFALSE){/* 請(qǐng)求切換任務(wù) */queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}/* 等待接收隊(duì)列項(xiàng)而阻塞的任務(wù)列表為空 */else if(xYieldRequired != pdFALSE){queueYIELD_IF_USING_PREEMPTION();}else{mtCOVERAGE_TEST_MARKER();}}#endif/* 退出臨界區(qū) */taskEXIT_CRITICAL();/* 成功 */return pdPASS;}/* 目前隊(duì)列已經(jīng)滿了,且不是覆蓋型插入 */else{/* 阻塞時(shí)間為0 */if(xTicksToWait == (TickType_t)0){taskEXIT_CRITICAL();traceQUEUE_SEND_FAILED(pxQueue);/* 返回隊(duì)列已滿錯(cuò)誤 */return errQUEUE_FULL;}/* 當(dāng)前節(jié)拍狀態(tài)還未記錄 */else if(xEntryTimeSet == pdFALSE){/* 記錄當(dāng)前節(jié)拍狀態(tài) */vTaskInternalSetTimeOutState(&xTimeOut);/* 當(dāng)前節(jié)拍狀態(tài)已經(jīng)記錄 */xEntryTimeSet = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}}/* 退出臨界區(qū) */taskEXIT_CRITICAL();/* 掛起調(diào)度器 */vTaskSuspendAll();/* 鎖定隊(duì)列 */prvLockQueue(pxQueue);/* 檢查任務(wù)是否超時(shí),并未超時(shí) */if(xTaskCheckForTimeOut(&xTimeOut, &xTicksToWait) == pdFALSE){/* 檢查隊(duì)列是否已滿,已經(jīng)滿了 */if(prvIsQueueFull(pxQueue) != pdFALSE){traceBLOCKING_ON_QUEUE_SEND(pxQueue);/* 將任務(wù)掛接到等待發(fā)送而阻塞的任務(wù)列表中,并將任務(wù)掛接到延時(shí)列表中 */vTaskPlaceOnEventList(&(pxQueue->xTasksWaitingToSend), xTicksToWait);/* 解鎖隊(duì)列 */prvUnlockQueue(pxQueue);/* 解除調(diào)度器掛起 */if(xTaskResumeAll() == pdFALSE){/* 請(qǐng)求切換 */portYIELD_WITHIN_API();}}/* 剛好隊(duì)列出現(xiàn)空位,下一次while循環(huán)重新插入 */else{/* 解鎖隊(duì)列 */prvUnlockQueue(pxQueue);/* 解除調(diào)度器掛起 */(void)xTaskResumeAll();}}/* 已經(jīng)超時(shí)或者超時(shí)之后 */else{/* 解鎖隊(duì)列 */prvUnlockQueue(pxQueue);/* 解除調(diào)度器掛起 */(void)xTaskResumeAll();traceQUEUE_SEND_FAILED(pxQueue);/* 隊(duì)列已滿 */return errQUEUE_FULL;}} }下面看一下prvCopyDataToQueue函數(shù),看看是怎么恢復(fù)優(yōu)先級(jí)的
從源代碼來(lái)看是通過(guò)xTaskPriorityDisinherit函數(shù)來(lái)恢復(fù)優(yōu)先級(jí)
/* 將隊(duì)列項(xiàng)拷貝到隊(duì)列中 */ static BaseType_t prvCopyDataToQueue(Queue_t *const pxQueue, const void *pvItemToQueue, const BaseType_t xPosition) {BaseType_t xReturn = pdFALSE;UBaseType_t uxMessagesWaiting;/* 隊(duì)列中隊(duì)列項(xiàng)數(shù) */uxMessagesWaiting = pxQueue->uxMessagesWaiting;/* 隊(duì)列項(xiàng)大小為0 */if(pxQueue->uxItemSize == (UBaseType_t)0){#if (configUSE_MUTEXES == 1){/* 隊(duì)列類型為互斥鎖 */if(pxQueue->uxQueueType == queueQUEUE_IS_MUTEX){/* 剝奪繼承優(yōu)先級(jí) */xReturn = xTaskPriorityDisinherit(pxQueue->u.xSemaphore.xMutexHolder);/* 互斥鎖持有者設(shè)置為空 */pxQueue->u.xSemaphore.xMutexHolder = NULL;}else{mtCOVERAGE_TEST_MARKER();}}#endif}/* 隊(duì)列項(xiàng)大小不為0,從隊(duì)列尾部插入 */else if(xPosition == queueSEND_TO_BACK){/* 將隊(duì)列項(xiàng)插入隊(duì)列 */(void)memcpy((void *)pxQueue->pcWriteTo, pvItemToQueue, (size_t)pxQueue->uxItemSize);/* 將隊(duì)列項(xiàng)寫入指針向后偏移一個(gè)隊(duì)列項(xiàng) */pxQueue->pcWriteTo += pxQueue->uxItemSize;/* 隊(duì)列項(xiàng)寫入指針已經(jīng)偏移到隊(duì)列尾部了 */if(pxQueue->pcWriteTo >= pxQueue->u.xQueue.pcTail){/* 將隊(duì)列項(xiàng)寫入指針偏移到頭部 */pxQueue->pcWriteTo = pxQueue->pcHead;}else{mtCOVERAGE_TEST_MARKER();}}/* 隊(duì)列項(xiàng)大小不為0,從隊(duì)列頭部插入/覆蓋插入 */else{/* 將隊(duì)列項(xiàng)插入隊(duì)列 */(void)memcpy((void *)pxQueue->u.xQueue.pcReadFrom, pvItemToQueue, (size_t)pxQueue->uxItemSize);/* 將隊(duì)列項(xiàng)讀出指針向前偏移一個(gè)隊(duì)列項(xiàng) */pxQueue->u.xQueue.pcReadFrom -= pxQueue->uxItemSize;/* 隊(duì)列項(xiàng)讀出指針已經(jīng)偏移到隊(duì)列頭部了 */if(pxQueue->u.xQueue.pcReadFrom < pxQueue->pcHead){/* 將隊(duì)列項(xiàng)讀出指針偏移到尾部 */pxQueue->u.xQueue.pcReadFrom = (pxQueue->u.xQueue.pcTail - pxQueue->uxItemSize);}else{mtCOVERAGE_TEST_MARKER();}/* 覆蓋式插入 */if(xPosition == queueOVERWRITE){/* 隊(duì)列項(xiàng)個(gè)數(shù)大于0 */if(uxMessagesWaiting > (UBaseType_t)0){/* 因?yàn)楦采w了一個(gè)隊(duì)列項(xiàng),所以隊(duì)列項(xiàng)數(shù)減一 */--uxMessagesWaiting;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}/* 隊(duì)列項(xiàng)數(shù)加一 */pxQueue->uxMessagesWaiting = uxMessagesWaiting + (UBaseType_t)1;return xReturn; }?
?
創(chuàng)建遞歸互斥鎖
遞歸互斥鎖和互斥鎖的創(chuàng)建過(guò)程是一樣的,只是互斥鎖的類型不同
#define xSemaphoreCreateMutex() xQueueCreateMutex(queueQUEUE_TYPE_MUTEX)?
?
獲取遞歸互斥鎖
和互斥鎖不同的是,同一任務(wù)可以多次獲取遞歸互斥鎖。因此,主要步驟為:
1.如果當(dāng)前任務(wù)不持有該互斥鎖,則申請(qǐng)持有互斥鎖,遞歸次數(shù)加一
2.如果當(dāng)前任務(wù)已經(jīng)持有該互斥鎖,則直接遞歸次數(shù)加一?
/* 獲取遞歸互斥鎖 */ BaseType_t xQueueTakeMutexRecursive(QueueHandle_t xMutex, TickType_t xTicksToWait) {BaseType_t xReturn;Queue_t *const pxMutex = (Queue_t *)xMutex;configASSERT(pxMutex);traceTAKE_MUTEX_RECURSIVE(pxMutex);/* 互斥鎖持有者為當(dāng)前任務(wù) */if(pxMutex->u.xSemaphore.xMutexHolder == xTaskGetCurrentTaskHandle()){/* 遞歸次數(shù)加一 */(pxMutex->u.xSemaphore.uxRecursiveCallCount)++;xReturn = pdPASS;}/* 互斥鎖持有者不為當(dāng)前任務(wù) */else{/* 持有該互斥鎖 */xReturn = xQueueSemaphoreTake(pxMutex, xTicksToWait);if(xReturn != pdFAIL){/* 遞歸次數(shù)加一 */(pxMutex->u.xSemaphore.uxRecursiveCallCount)++;}else{traceTAKE_MUTEX_RECURSIVE_FAILED(pxMutex);}}return xReturn; }?
?
釋放遞歸互斥鎖
和互斥鎖不同的是,同一任務(wù)可以多次獲取遞歸互斥鎖,解除同等次數(shù)才能徹底釋放。因此,主要步驟為:
1.遞歸次數(shù)減一
2.當(dāng)遞歸次數(shù)減完,徹底釋放互斥鎖
/* 釋放遞歸互斥鎖 */ BaseType_t xQueueGiveMutexRecursive(QueueHandle_t xMutex) {BaseType_t xReturn;Queue_t *const pxMutex = (Queue_t *)xMutex;configASSERT(pxMutex);/* 互斥鎖持有者為當(dāng)前任務(wù) */if(pxMutex->u.xSemaphore.xMutexHolder == xTaskGetCurrentTaskHandle()){traceGIVE_MUTEX_RECURSIVE(pxMutex);/* 遞歸次數(shù)減一 */(pxMutex->u.xSemaphore.uxRecursiveCallCount)--;/* 遞歸次數(shù)減到0 */if(pxMutex->u.xSemaphore.uxRecursiveCallCount == (UBaseType_t)0){/* 徹底釋放互斥鎖 */(void)xQueueGenericSend(pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK);}else{mtCOVERAGE_TEST_MARKER();}xReturn = pdPASS;}/* 互斥鎖持有者不為當(dāng)前任務(wù),直接返回錯(cuò)誤 */else{xReturn = pdFAIL;traceGIVE_MUTEX_RECURSIVE_FAILED(pxMutex);}return xReturn; }?
?
優(yōu)先級(jí)繼承和剝奪
從上面的分析,我們知道優(yōu)先級(jí)繼承和剝奪函數(shù)如下
優(yōu)先級(jí)繼承:xTaskPriorityInherit
互斥鎖阻塞超時(shí)后,恢復(fù)優(yōu)先級(jí):prvGetDisinheritPriorityAfterTimeout和vTaskPriorityDisinheritAfterTimeout
解放互斥鎖,恢復(fù)優(yōu)先級(jí):xTaskPriorityDisinherit
?
下面我們一個(gè)一個(gè)來(lái)分析,首先是xTaskPriorityInherit
1.當(dāng)前任務(wù)優(yōu)先級(jí)和互斥鎖持有任務(wù)優(yōu)先級(jí)進(jìn)行比較,將互斥鎖持有任務(wù)的優(yōu)先級(jí)更新為更高的那個(gè)優(yōu)先級(jí)
2.將互斥鎖持有任務(wù)按照新的優(yōu)先級(jí)重新放到就緒列表中
/* 任務(wù)優(yōu)先級(jí)繼承 */ BaseType_t xTaskPriorityInherit(TaskHandle_t const pxMutexHolder) {TCB_t *const pxMutexHolderTCB = pxMutexHolder;BaseType_t xReturn = pdFALSE;/* 互斥鎖持有者不為空 */if(pxMutexHolder != NULL){/* 互斥鎖持有者優(yōu)先級(jí)小于當(dāng)前任務(wù)優(yōu)先級(jí) */if(pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority){/* 將互斥鎖持有者的事件列表項(xiàng)值(任務(wù)優(yōu)先級(jí))設(shè)置為當(dāng)前任務(wù)事件列表項(xiàng)值(任務(wù)優(yōu)先級(jí)) */if((listGET_LIST_ITEM_VALUE(&(pxMutexHolderTCB->xEventListItem)) & taskEVENT_LIST_ITEM_VALUE_IN_USE) == 0UL){listSET_LIST_ITEM_VALUE(&(pxMutexHolderTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)pxCurrentTCB->uxPriority);}else{mtCOVERAGE_TEST_MARKER();}/* 判斷互斥鎖持有者是否就緒,就緒 */if(listIS_CONTAINED_WITHIN(&(pxReadyTasksLists[pxMutexHolderTCB->uxPriority]), &(pxMutexHolderTCB->xStateListItem)) != pdFALSE){/* 將互斥鎖持有者從就緒列表中移除,移除完后列表中沒(méi)有任務(wù) */if(uxListRemove(&(pxMutexHolderTCB->xStateListItem)) == (UBaseType_t)0){/* 檢查就緒列表中是否有任務(wù),如果沒(méi)有將該優(yōu)先級(jí)從當(dāng)前任務(wù)優(yōu)先級(jí)記錄中清除 */taskRESET_READY_PRIORITY(pxMutexHolderTCB->uxPriority);}else{mtCOVERAGE_TEST_MARKER();}/* 互斥鎖持有者優(yōu)先級(jí)設(shè)置為當(dāng)前任務(wù)優(yōu)先級(jí) */pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;/* 將互斥鎖持有者重新插入新優(yōu)先級(jí)的就緒列表中 */prvAddTaskToReadyList(pxMutexHolderTCB);}/* 互斥鎖持有者并不在就緒態(tài) */else{/* 互斥鎖持有者優(yōu)先級(jí)設(shè)置為當(dāng)前任務(wù)優(yōu)先級(jí) */pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;}traceTASK_PRIORITY_INHERIT(pxMutexHolderTCB, pxCurrentTCB->uxPriority);/* 返回繼承了優(yōu)先級(jí) */xReturn = pdTRUE;}/* 互斥鎖持有者優(yōu)先級(jí)不小于當(dāng)前任務(wù)優(yōu)先級(jí) */else{/* 互斥鎖持有者基礎(chǔ)優(yōu)先級(jí)小于當(dāng)前任務(wù)優(yōu)先級(jí),說(shuō)明繼承了其它任務(wù)優(yōu)先級(jí) */if(pxMutexHolderTCB->uxBasePriority < pxCurrentTCB->uxPriority){/* 返回繼承了優(yōu)先級(jí) */xReturn = pdTRUE;}/* 沒(méi)有繼承優(yōu)先級(jí) */else{mtCOVERAGE_TEST_MARKER();}}}else{mtCOVERAGE_TEST_MARKER();}return xReturn; }?
prvGetDisinheritPriorityAfterTimeout和vTaskPriorityDisinheritAfterTimeout
用法
UBaseType_t uxHighestWaitingPriority;/* 獲取剩下所有等待互斥鎖任務(wù)的最高優(yōu)先級(jí) */ uxHighestWaitingPriority = prvGetDisinheritPriorityAfterTimeout(pxQueue); /* 超時(shí)之后剝奪繼承優(yōu)先級(jí) */ vTaskPriorityDisinheritAfterTimeout(pxQueue->u.xSemaphore.xMutexHolder, uxHighestWaitingPriority);prvGetDisinheritPriorityAfterTimeout獲取超時(shí)后可能需要?jiǎng)儕Z的優(yōu)先級(jí)
1.獲取等待互斥鎖阻塞任務(wù)中的最高優(yōu)先級(jí)
/* 獲取剩下所有等待互斥鎖任務(wù)的最高優(yōu)先級(jí) */ static UBaseType_t prvGetDisinheritPriorityAfterTimeout(const Queue_t *const pxQueue) {UBaseType_t uxHighestPriorityOfWaitingTasks;/* 因?yàn)槟貌坏交コ怄i而阻塞的任務(wù)列表不為空 */if(listCURRENT_LIST_LENGTH(&(pxQueue->xTasksWaitingToReceive)) > 0U){/* 獲取隊(duì)列中優(yōu)先級(jí)最高的任務(wù) */uxHighestPriorityOfWaitingTasks = (UBaseType_t)configMAX_PRIORITIES - (UBaseType_t)listGET_ITEM_VALUE_OF_HEAD_ENTRY(&(pxQueue->xTasksWaitingToReceive));}/* 因?yàn)槟貌坏交コ怄i而阻塞的任務(wù)列表為空 */else{/* 最高的優(yōu)先級(jí)為空閑任務(wù)優(yōu)先級(jí) */uxHighestPriorityOfWaitingTasks = tskIDLE_PRIORITY;}return uxHighestPriorityOfWaitingTasks; }vTaskPriorityDisinheritAfterTimeout超時(shí)后剝奪優(yōu)先級(jí)
1.先計(jì)算剝奪繼承當(dāng)前任務(wù)優(yōu)先級(jí)后,需要重新設(shè)置的繼承優(yōu)先級(jí)
2.檢查互斥鎖持有者的優(yōu)先級(jí)是否繼承自當(dāng)前任務(wù)
3.如果互斥鎖持有者的優(yōu)先級(jí)是否繼承自當(dāng)前任務(wù),那么就需要重新設(shè)置的繼承優(yōu)先級(jí)
4.設(shè)置新的優(yōu)先級(jí),并將互斥鎖持有者從原就緒列表中轉(zhuǎn)移到新的就緒列表中
注意:FreeRTOS中處理的并不完美,如果互斥鎖持有者如果持有不止一把鎖的話,即使互斥鎖持有者的優(yōu)先級(jí)是否繼承自當(dāng)前任務(wù)也不進(jìn)行剝奪,這可能導(dǎo)致互斥鎖的持有任務(wù)優(yōu)先級(jí)并不完全準(zhǔn)確。
/* 超時(shí)之后剝奪繼承優(yōu)先級(jí) */ void vTaskPriorityDisinheritAfterTimeout(TaskHandle_t const pxMutexHolder, UBaseType_t uxHighestPriorityWaitingTask) {TCB_t *const pxTCB = pxMutexHolder;UBaseType_t uxPriorityUsedOnEntry, uxPriorityToUse;const UBaseType_t uxOnlyOneMutexHeld = (UBaseType_t)1;/* 互斥鎖持有者不為空 */if(pxMutexHolder != NULL){configASSERT(pxTCB->uxMutexesHeld);/* 互斥鎖持有者基礎(chǔ)優(yōu)先級(jí)小于等待持有互斥鎖任務(wù)的最高優(yōu)先級(jí),說(shuō)明需要繼承優(yōu)先級(jí) */if(pxTCB->uxBasePriority < uxHighestPriorityWaitingTask){/* 將要被設(shè)置的優(yōu)先級(jí) */uxPriorityToUse = uxHighestPriorityWaitingTask;}/* 不需要繼承優(yōu)先級(jí) */else{/* 將要被設(shè)置的優(yōu)先級(jí) */uxPriorityToUse = pxTCB->uxBasePriority;}/* 互斥鎖持有者優(yōu)先級(jí)不等于剩下任務(wù)最高優(yōu)先級(jí),說(shuō)明之前互斥鎖持有者優(yōu)先級(jí)繼承于當(dāng)前任務(wù) */if(pxTCB->uxPriority != uxPriorityToUse){/* 互斥鎖持有者只持有一個(gè)互斥鎖 */if(pxTCB->uxMutexesHeld == uxOnlyOneMutexHeld){configASSERT(pxTCB != pxCurrentTCB);traceTASK_PRIORITY_DISINHERIT(pxTCB, pxTCB->uxBasePriority);/* 保存任務(wù)優(yōu)先級(jí) */uxPriorityUsedOnEntry = pxTCB->uxPriority;/* 互斥鎖持有者優(yōu)先級(jí)設(shè)置為剩下等待互斥鎖任務(wù)的最高優(yōu)先級(jí) */pxTCB->uxPriority = uxPriorityToUse;/* 將事件列表值也改成剩下等待互斥鎖任務(wù)的最高優(yōu)先級(jí) */if((listGET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem)) & taskEVENT_LIST_ITEM_VALUE_IN_USE) == 0UL){listSET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)uxPriorityToUse);}else{mtCOVERAGE_TEST_MARKER();}/* 把任務(wù)從當(dāng)前就緒列表中移除 */if(listIS_CONTAINED_WITHIN(&(pxReadyTasksLists[uxPriorityUsedOnEntry] ), &(pxTCB->xStateListItem)) != pdFALSE){if(uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0){taskRESET_READY_PRIORITY(pxTCB->uxPriority);}else{mtCOVERAGE_TEST_MARKER();}/* 重新添加到新優(yōu)先級(jí)就緒列表中 */prvAddTaskToReadyList(pxTCB);}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();} }?
xTaskPriorityDisinherit,剝奪優(yōu)先級(jí)繼承
1.先判斷是否繼承了優(yōu)先級(jí)
2.如果繼承了優(yōu)先級(jí),恢復(fù)基礎(chǔ)優(yōu)先級(jí),并將任務(wù)根據(jù)新優(yōu)先級(jí)從原就緒列表中轉(zhuǎn)移到新的就緒列表
注意:FreeRTOS中處理的并不完美,如果互斥鎖持有者如果持有不止一把鎖的話,并不會(huì)剝奪繼承優(yōu)先級(jí),這可能導(dǎo)致互斥鎖的持有任務(wù)優(yōu)先級(jí)并不完全準(zhǔn)確。
/* 剝奪繼承優(yōu)先級(jí) */ BaseType_t xTaskPriorityDisinherit(TaskHandle_t const pxMutexHolder) {TCB_t *const pxTCB = pxMutexHolder;BaseType_t xReturn = pdFALSE;/* 互斥鎖持有者不為空 */if(pxMutexHolder != NULL){configASSERT(pxTCB == pxCurrentTCB);configASSERT(pxTCB->uxMutexesHeld);/* 任務(wù)持有鎖數(shù)量減一 */(pxTCB->uxMutexesHeld)--;/* 任務(wù)優(yōu)先級(jí)不等于基礎(chǔ)優(yōu)先級(jí),說(shuō)明繼承了優(yōu)先級(jí) */if(pxTCB->uxPriority != pxTCB->uxBasePriority){/* 任務(wù)持有鎖數(shù)量為0 */if(pxTCB->uxMutexesHeld == (UBaseType_t)0){/* 將互斥鎖持有者從就緒列表中移除 */if(uxListRemove(&(pxTCB->xStateListItem)) == (UBaseType_t)0){/* 檢查就緒列表中是否有任務(wù),如果沒(méi)有將該優(yōu)先級(jí)從當(dāng)前任務(wù)優(yōu)先級(jí)記錄中清除 */taskRESET_READY_PRIORITY(pxTCB->uxPriority);}else{mtCOVERAGE_TEST_MARKER();}traceTASK_PRIORITY_DISINHERIT(pxTCB, pxTCB->uxBasePriority);/* 將任務(wù)優(yōu)先級(jí)復(fù)原為基礎(chǔ)優(yōu)先級(jí) */pxTCB->uxPriority = pxTCB->uxBasePriority;/* 將事件列表項(xiàng)值重新設(shè)為基礎(chǔ)優(yōu)先級(jí)值 */listSET_LIST_ITEM_VALUE(&(pxTCB->xEventListItem), (TickType_t)configMAX_PRIORITIES - (TickType_t)pxTCB->uxPriority);/* 將任務(wù)重新加入新優(yōu)先級(jí)任務(wù)列表 */prvAddTaskToReadyList(pxTCB);xReturn = pdTRUE;}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}}else{mtCOVERAGE_TEST_MARKER();}return xReturn; }?
?
總結(jié)
以上是生活随笔為你收集整理的FreeRTOS互斥锁的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 不修条地铁,都不好意思叫自己大城市
- 下一篇: Adidas、金拱门、KFC、乐天玛特,