基础知识
创建互斥量
#define queueQUEUE_TYPE_MUTEX ( ( uint8_t ) 1U )
#define xSemaphoreCreateMutex() xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType )
-> const UBaseType_t uxMutexLength = ( UBaseType_t ) 1, uxMutexSize = ( UBaseType_t ) 0;
-> pxNewQueue = ( Queue_t * ) xQueueGenericCreate( uxMutexLength, uxMutexSize, ucQueueType ); // 创建长度为1,大小为0的队列,作为互斥量
-> prvInitialiseMutex( pxNewQueue ); // 初始化互斥量特殊参数
-> pxNewQueue->pxMutexHolder = NULL; // 互斥量持有者
-> pxNewQueue->uxQueueType = queueQUEUE_IS_MUTEX; // 队列类型为互斥量
-> pxNewQueue->u.uxRecursiveCallCount = 0; //递归互斥
-> ( void ) xQueueGenericSend( pxNewQueue, NULL, ( TickType_t ) 0U, queueSEND_TO_BACK ); // 确保互斥量值为初始状态
根据上面的定义,可知创建互斥量本质就是创建队列。长度(第一个参数)为1,大小(第二个参数)为0
获取互斥量
通过队列获取互斥量 函数与获取信号量 的方式是一样的。可以参考:[FreeRTOS 内部实现] 信号量
#define xSemaphoreTake( xSemaphore, xBlockTime ) xQueueSemaphoreTake( ( xSemaphore ), ( xBlockTime ) )
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )
-> taskENTER_CRITICAL(); // 关中断
-> const UBaseType_t uxSemaphoreCount = pxQueue->uxMessagesWaiting; // 获取当前信号量值
-> pxQueue->uxMessagesWaiting = uxSemaphoreCount - ( UBaseType_t ) 1; // 信号量-1
-> if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) // 如果该队列是互斥量并且获取到互斥量
pxQueue->pxMutexHolder = ( int8_t * ) pvTaskIncrementMutexHeldCount(); // 记录当前互斥量持有者
-> if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX ) //如果该队列是互斥量并且没有获取到互斥量
xInheritanceOccurred = xTaskPriorityInherit( ( void * ) pxQueue->pxMutexHolder ); // 任务优先级继承
-> if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority ) // 当前的任务优先级大于持有互斥量任务的优先级
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ), &( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE ) // 持有互斥量的任务是否在状态链表中
if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) // 从状态链表中移除
taskRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority );
pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority; // 设置高优先级
prvAddTaskToReadyList( pxMutexHolderTCB ); // 持有互斥量的任务添加到就绪列表中
-> vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
// 1、当前的任务加入到队列的xTasksWaitingToReceive链表中;
// 2、当前的任务从ReadyList移动到DelayList
释放互斥量
通过队列释放互斥量 函数与释放信号量 的方式是一样的。可以参考:[FreeRTOS 内部实现] 信号量
#define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U )
#define xSemaphoreGive( xSemaphore ) xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
BaseType_t xQueueGenericSend( QueueHandle_t xQueue, const void * const pvItemToQueue, TickType_t xTicksToWait, const BaseType_t xCopyPosition )
-> taskENTER_CRITICAL(); // 关中断 portDISABLE_INTERRUPTS();
-> xYieldRequired = prvCopyDataToQueue( pxQueue, pvItemToQueue, xCopyPosition );
// 不会写数据,但是会将 uxMessagesWaiting +1, 取消当前任务继承
-> if( pxQueue->uxQueueType == queueQUEUE_IS_MUTEX )
xReturn = xTaskPriorityDisinherit( ( void * ) pxQueue->pxMutexHolder ); // 取消继承
-> if( pxTCB->uxPriority != pxTCB->uxBasePriority ) // 当前的优先级与之前备份的优先级不同
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 ) // 从StateList移除
-> traceTASK_PRIORITY_DISINHERIT( pxTCB, pxTCB->uxBasePriority );
-> pxTCB->uxPriority = pxTCB->uxBasePriority; // 恢复之前优先级
-> listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ), ( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority ); // 重置事件链表值
-> prvAddTaskToReadyList( pxTCB );
-> --uxMessagesWaiting;