引言
信号量和互斥量是FreeRTOS中最重要的同步原语,它们基于队列机制实现,但提供了更高层次的抽象。本文将深入分析FreeRTOS中各种信号量和互斥量的实现原理,揭示它们在任务同步和资源保护中的作用机制。
1. 信号量的本质:队列的特殊应用
1.1 信号量与队列的关系
FreeRTOS中的信号量本质上是特殊的队列:
/* 信号量实际上是队列句柄的别名 */ typedef QueueHandle_t SemaphoreHandle_t; /* 信号量的关键参数定义 */ #define semBINARY_SEMAPHORE_QUEUE_LENGTH ( ( uint8_t ) 1U ) #define semSEMAPHORE_QUEUE_ITEM_LENGTH ( ( uint8_t ) 0U ) #define semGIVE_BLOCK_TIME ( ( TickType_t ) 0U )
设计精髓:
-
队列长度为1:二进制信号量只能有0或1两种状态
-
项目大小为0:信号量不存储数据,只关心计数
-
复用队列机制:充分利用已有的队列实现
1.2 信号量在队列结构中的表示
/* 从queue.c可以看出信号量如何使用队列结构 */
typedef struct QueueDefinition
{
int8_t * pcHead; /* 对于信号量,指向队列结构本身 */
int8_t * pcWriteTo; /* 写指针 */
union
{
QueuePointers_t xQueue; /* 普通队列使用 */
SemaphoreData_t xSemaphore; /* 信号量/互斥量专用 */
} u;
List_t xTasksWaitingToSend; /* 等待释放信号量的任务 */
List_t xTasksWaitingToReceive; /* 等待获取信号量的任务 */
volatile UBaseType_t uxMessagesWaiting; /* 信号量计数值 */
UBaseType_t uxLength; /* 最大计数值 */
UBaseType_t uxItemSize; /* 对于信号量为0 */
/* 其他字段... */
} xQUEUE;
/* 信号量专用数据结构 */
typedef struct SemaphoreData
{
TaskHandle_t xMutexHolder; /* 互斥量持有者 */
UBaseType_t uxRecursiveCallCount; /* 递归调用计数 */
} SemaphoreData_t;
2. 二进制信号量深度解析
2.1 二进制信号量的创建
/* 动态创建二进制信号量 */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define xSemaphoreCreateBinary() \
xQueueGenericCreate( ( UBaseType_t ) 1, \
semSEMAPHORE_QUEUE_ITEM_LENGTH, \
queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif
/* 静态创建二进制信号量 */
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
#define xSemaphoreCreateBinaryStatic( pxSemaphoreBuffer ) \
xQueueGenericCreateStatic( ( UBaseType_t ) 1, \
semSEMAPHORE_QUEUE_ITEM_LENGTH, \
NULL, \
pxSemaphoreBuffer, \
queueQUEUE_TYPE_BINARY_SEMAPHORE )
#endif
/* 旧版本的创建宏(已废弃但仍支持) */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define vSemaphoreCreateBinary( xSemaphore ) \
do { \
( xSemaphore ) = xQueueGenericCreate( ( UBaseType_t ) 1, \
semSEMAPHORE_QUEUE_ITEM_LENGTH, \
queueQUEUE_TYPE_BINARY_SEMAPHORE ); \
if( ( xSemaphore ) != NULL ) \
{ \
( void ) xSemaphoreGive( ( xSemaphore ) ); \
} \
} while( 0 )
#endif
关键差异:
-
xSemaphoreCreateBinary():创建时信号量为空(需要先Give) -
vSemaphoreCreateBinary():创建时信号量为满(可以直接Take)
2.2 二进制信号量的操作
/* Give操作:释放信号量 */ #define xSemaphoreGive( xSemaphore ) \ xQueueGenericSend( ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK ) /* Take操作:获取信号量 */ #define xSemaphoreTake( xSemaphore, xBlockTime ) \ xQueueReceive( ( xSemaphore ), NULL, ( xBlockTime ) ) /* 中断安全版本 */ #define xSemaphoreGiveFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \ xQueueGiveFromISR( ( xSemaphore ), ( pxHigherPriorityTaskWoken ) ) #define xSemaphoreTakeFromISR( xSemaphore, pxHigherPriorityTaskWoken ) \ xQueueReceiveFromISR( ( xSemaphore ), NULL, ( pxHigherPriorityTaskWoken ) )
2.3 二进制信号量应用示例
/* 任务同步示例 */
SemaphoreHandle_t xBinarySemaphore;
/* 生产者任务 */
void vProducerTask( void *pvParameters )
{
for( ;; )
{
/* 执行某些工作 */
performWork();
/* 通知消费者任务 */
xSemaphoreGive( xBinarySemaphore );
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
}
/* 消费者任务 */
void vConsumerTask( void *pvParameters )
{
for( ;; )
{
/* 等待生产者通知 */
if( xSemaphoreTake( xBinarySemaphore, portMAX_DELAY ) == pdTRUE )
{
/* 处理通知 */
processNotification();
}
}
}
/* 中断服务程序示例 */
void vButtonISR( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
/* 从中断中释放信号量 */
xSemaphoreGiveFromISR( xBinarySemaphore, &xHigherPriorityTaskWoken );
/* 如果需要,执行上下文切换 */
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
3. 计数信号量深度解析
3.1 计数信号量的创建
/* 动态创建计数信号量 */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define xSemaphoreCreateCounting( uxMaxCount, uxInitialCount ) \
xQueueCreateCountingSemaphore( ( uxMaxCount ), ( uxInitialCount ) )
#endif
/* 静态创建计数信号量 */
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
#define xSemaphoreCreateCountingStatic( uxMaxCount, uxInitialCount, pxSemaphoreBuffer ) \
xQueueCreateCountingSemaphoreStatic( ( uxMaxCount ), ( uxInitialCount ), ( pxSemaphoreBuffer ) )
#endif
/* 计数信号量创建函数的实现 */
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,
queueQUEUE_TYPE_COUNTING_SEMAPHORE );
if( xHandle != NULL )
{
( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount;
traceCREATE_COUNTING_SEMAPHORE();
}
else
{
traceCREATE_COUNTING_SEMAPHORE_FAILED();
}
return xHandle;
}
3.2 计数信号量的特点
/* 计数信号量状态检查 */
UBaseType_t uxSemaphoreGetCount( SemaphoreHandle_t xSemaphore )
{
UBaseType_t uxReturn;
configASSERT( xSemaphore );
taskENTER_CRITICAL();
{
uxReturn = ( ( Queue_t * ) xSemaphore )->uxMessagesWaiting;
}
taskEXIT_CRITICAL();
return uxReturn;
}
/* 检查信号量是否可用 */
#define xSemaphoreGetCount( xSemaphore ) \
uxQueueMessagesWaiting( ( QueueHandle_t ) ( xSemaphore ) )
3.3 计数信号量应用示例
/* 资源池管理示例 */
#define MAX_RESOURCES 5
SemaphoreHandle_t xResourceSemaphore;
/* 初始化资源池 */
void vInitializeResourcePool( void )
{
/* 创建计数信号量,初始值等于最大资源数 */
xResourceSemaphore = xSemaphoreCreateCounting( MAX_RESOURCES, MAX_RESOURCES );
if( xResourceSemaphore == NULL )
{
/* 创建失败处理 */
configASSERT( 0 );
}
}
/* 获取资源 */
BaseType_t xAcquireResource( TickType_t xTimeout )
{
return xSemaphoreTake( xResourceSemaphore, xTimeout );
}
/* 释放资源 */
void vReleaseResource( void )
{
xSemaphoreGive( xResourceSemaphore );
}
/* 使用资源的任务 */
void vResourceUserTask( void *pvParameters )
{
for( ;; )
{
/* 尝试获取资源 */
if( xAcquireResource( pdMS_TO_TICKS( 1000 ) ) == pdTRUE )
{
/* 使用资源 */
useResource();
/* 释放资源 */
vReleaseResource();
}
else
{
/* 获取资源超时 */
handleResourceTimeout();
}
vTaskDelay( pdMS_TO_TICKS( 100 ) );
}
}
4. 互斥量深度解析
4.1 互斥量的本质
互斥量是特殊的二进制信号量,具有以下特殊性质:
-
所有权:只有获取互斥量的任务才能释放它
-
优先级继承:防止优先级反转问题
-
递归支持:支持同一任务多次获取
/* 互斥量创建 */
#if ( configSUPPORT_DYNAMIC_ALLOCATION == 1 )
#define xSemaphoreCreateMutex() \
xQueueCreateMutex( queueQUEUE_TYPE_MUTEX )
#endif
#if ( configSUPPORT_STATIC_ALLOCATION == 1 )
#define xSemaphoreCreateMutexStatic( pxMutexBuffer ) \
xQueueCreateMutexStatic( queueQUEUE_TYPE_MUTEX, ( pxMutexBuffer ) )
#endif
/* 互斥量创建函数实现 */
QueueHandle_t xQueueCreateMutex( const uint8_t ucQueueType )
{
QueueHandle_t xNewQueue;
const UBaseType_t uxMutexLength = ( UBaseType_t ) 1;
const UBaseType_t uxMutexSize = ( UBaseType_t ) 0;
xNewQueue = xQueueGenericCreate( uxMutexLength,
uxMutexSize,
ucQueueType );
if( xNewQueue != NULL )
{
/* 初始化互斥量为可用状态 */
( ( Queue_t * ) xNewQueue )->u.xSemaphore.xMutexHolder = NULL;
( ( Queue_t * ) xNewQueue )->uxQueueType = ucQueueType;
/* 初始释放互斥量 */
( void ) xQueueGenericSend( xNewQueue, NULL, ( TickType_t ) 0U, queueSEND_TO_BACK );
traceCREATE_MUTEX( xNewQueue );
}
else
{
traceCREATE_MUTEX_FAILED();
}
return xNewQueue;
}
4.2 优先级继承机制
/* 优先级继承的核心实现 */
static BaseType_t prvCopyDataToQueue( Queue_t * const pxQueue,
const void *pvItemToQueue,
const BaseType_t xPosition )
{
BaseType_t xReturn = pdFALSE;
UBaseType_t uxMessagesWaiting;
/* 对于互斥量,需要处理优先级继承 */
if( pxQueue->uxQueueType == queueQUEUE_TYPE_MUTEX )
{
/* 释放互斥量时的处理 */
( ( Queue_t * ) pxQueue )->u.xSemaphore.xMutexHolder = NULL;
/* 如果有任务在等待,可能需要调整优先级 */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToReceive ) ) == pdFALSE )
{
/* 获取等待任务中优先级最高的 */
if( xTaskPriorityInherit( ( void * ) pxQueue->u.xSemaphore.xMutexHolder ) != pdFALSE )
{
/* 需要进行任务切换 */
xReturn = queueYIELD_IF_USING_PREEMPTION;
}
}
}
uxMessagesWaiting = pxQueue->uxMessagesWaiting;
if( xPosition == queueSEND_TO_BACK )
{
/* 正常的队列发送操作 */
( void ) memcpy( ( void * ) pxQueue->pcWriteTo, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );
pxQueue->pcWriteTo += pxQueue->uxItemSize;
if( pxQueue->pcWriteTo >= pxQueue->pcTail )
{
pxQueue->pcWriteTo = pxQueue->pcHead;
}
}
else
{
/* 发送到队列前端 */
( void ) memcpy( ( void * ) pxQueue->u.xQueue.pcReadFrom, pvItemToQueue, ( size_t ) pxQueue->uxItemSize );
pxQueue->u.xQueue.pcReadFrom -= pxQueue->uxItemSize;
if( pxQueue->u.xQueue.pcReadFrom < pxQueue->pcHead )
{
pxQueue->u.xQueue.pcReadFrom = ( pxQueue->pcTail - pxQueue->uxItemSize );
}
pxQueue->uxMessagesWaiting = uxMessagesWaiting + ( UBaseType_t ) 1;
if( pxQueue->uxMessagesWaiting > pxQueue->uxLength )
{
pxQueue->uxMessagesWaiting = pxQueue->uxLength;
}
}
return xReturn;
}
4.3 互斥量的获取和释放
/* 互斥量获取 */
#define xSemaphoreTake( xSemaphore, xBlockTime ) \
xQueueReceive( ( xSemaphore ), NULL, ( xBlockTime ) )
/* 互斥量释放 */
#define xSemaphoreGive( xSemaphore ) \
xQueueGenericSend( ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )
/* 互斥量获取的内部实现(简化版) */
BaseType_t xQueueReceive( QueueHandle_t xQueue,
void * const pvBuffer,
TickType_t xTicksToWait )
{
BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut;
Queue_t * const pxQueue = xQueue;
for( ;; )
{
taskENTER_CRITICAL();
{
const UBaseType_t uxMessagesWaiting = pxQueue->uxMessagesWaiting;
if( uxMessagesWaiting > ( UBaseType_t ) 0 )
{
/* 有可用的互斥量 */
if( pxQueue->uxQueueType == queueQUEUE_TYPE_MUTEX )
{
/* 设置互斥量持有者 */
pxQueue->u.xSemaphore.xMutexHolder = xTaskGetCurrentTaskHandle();
}
pxQueue->uxMessagesWaiting = uxMessagesWaiting - ( UBaseType_t ) 1;
/* 唤醒等待发送的任务 */
if( listLIST_IS_EMPTY( &( pxQueue->xTasksWaitingToSend ) ) == pdFALSE )
{
if( xTaskRemoveFromEventList( &( pxQueue->xTasksWaitingToSend ) ) != pdFALSE )
{
queueYIELD_IF_USING_PREEMPTION();
}
}
taskEXIT_CRITICAL();
return pdPASS;
}
else
{
if( xTicksToWait == ( TickType_t ) 0 )
{
/* 不等待,直接返回 */
taskEXIT_CRITICAL();
return errQUEUE_EMPTY;
}
else if( xEntryTimeSet == pdFALSE )
{
/* 设置超时时间 */
vTaskInternalSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
}
}
taskEXIT_CRITICAL();
/* 挂起任务等待互斥量 */
vTaskSuspendAll();
{
/* 将任务添加到等待列表 */
vTaskPlaceOnEventList( &( pxQueue->xTasksWaitingToReceive ), xTicksToWait );
}
( void ) xTaskResumeAll();
/* 检查是否超时 */
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) != pdFALSE )
{
return errQUEUE_EMPTY;
}
}
}
4.4 互斥量应用示例
/* 共享资源保护示例 */
SemaphoreHandle_t xMutex;
int sharedResource = 0;
/* 初始化互斥量 */
void vInitializeMutex( void )
{
xMutex = xSemaphoreCreateMutex();
if( xMutex == NULL )
{
/* 创建失败处理 */
configASSERT( 0 );
}
}
/* 安全访问共享资源 */
void vSafeAccessResource( void )
{
/* 获取互斥量 */
if( xSemaphoreTake( xMutex, pdMS_TO_TICKS( 1000 ) ) == pdTRUE )
{
/* 临界区:安全访问共享资源 */
sharedResource++;
/* 模拟一些处理时间 */
vTaskDelay( pdMS_TO_TICKS( 10 ) );
sharedResource--;
/* 释放互斥量 */
xSemaphoreGive( xMutex );
}
else
{
/* 获取互斥量超时 */
handleMutexTimeout();
}
}
/* 多个任务安全访问共享资源 */
void vTask1( void *pvParameters )
{
for( ;; )
{
vSafeAccessResource();
vTaskDelay( pdMS_TO_TICKS( 100 ) );
}
}
void vTask2( void *pvParameters )
{
for( ;; )
{
vSafeAccessResource();
vTaskDelay( pdMS_TO_TICKS( 150 ) );
}
}
5. 递归互斥量深度解析
5.1 递归互斥量的创建
/* 递归互斥量创建 */
#if ( ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) )
#define xSemaphoreCreateRecursiveMutex() \
xQueueCreateMutex( queueQUEUE_TYPE_RECURSIVE_MUTEX )
#endif
#if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configUSE_RECURSIVE_MUTEXES == 1 ) )
#define xSemaphoreCreateRecursiveMutexStatic( pxMutexBuffer ) \
xQueueCreateMutexStatic( queueQUEUE_TYPE_RECURSIVE_MUTEX, pxMutexBuffer )
#endif
5.2 递归互斥量的操作
/* 递归获取互斥量 */
#if ( configUSE_RECURSIVE_MUTEXES == 1 )
BaseType_t xSemaphoreTakeRecursive( SemaphoreHandle_t xMutex,
TickType_t xTicksToWait )
{
BaseType_t xReturn;
Queue_t * const pxMutex = ( Queue_t * ) xMutex;
configASSERT( pxMutex );
configASSERT( pxMutex->uxQueueType == queueQUEUE_TYPE_RECURSIVE_MUTEX );
taskENTER_CRITICAL();
{
/* 检查当前任务是否已经持有互斥量 */
if( pxMutex->u.xSemaphore.xMutexHolder == xTaskGetCurrentTaskHandle() )
{
/* 递归调用计数增加 */
( pxMutex->u.xSemaphore.uxRecursiveCallCount )++;
xReturn = pdPASS;
}
else
{
/* 尝试获取互斥量 */
xReturn = xQueueReceive( pxMutex, NULL, xTicksToWait );
if( xReturn != pdFAIL )
{
/* 初始化递归计数 */
( pxMutex->u.xSemaphore.uxRecursiveCallCount ) = 1;
}
}
}
taskEXIT_CRITICAL();
return xReturn;
}
#endif
/* 递归释放互斥量 */
#if ( configUSE_RECURSIVE_MUTEXES == 1 )
BaseType_t xSemaphoreGiveRecursive( SemaphoreHandle_t xMutex )
{
BaseType_t xReturn;
Queue_t * const pxMutex = ( Queue_t * ) xMutex;
configASSERT( pxMutex );
configASSERT( pxMutex->uxQueueType == queueQUEUE_TYPE_RECURSIVE_MUTEX );
/* 只有持有者才能释放 */
if( pxMutex->u.xSemaphore.xMutexHolder == xTaskGetCurrentTaskHandle() )
{
taskENTER_CRITICAL();
{
/* 递归计数减少 */
( pxMutex->u.xSemaphore.uxRecursiveCallCount )--;
/* 只有当计数为0时才真正释放互斥量 */
if( pxMutex->u.xSemaphore.uxRecursiveCallCount == ( UBaseType_t ) 0 )
{
( void ) xQueueGenericSend( pxMutex, NULL, queueMUTEX_GIVE_BLOCK_TIME, queueSEND_TO_BACK );
}
xReturn = pdPASS;
}
taskEXIT_CRITICAL();
}
else
{
/* 非持有者尝试释放 */
xReturn = pdFAIL;
}
return xReturn;
}
#endif
5.3 递归互斥量应用示例
/* 递归函数保护示例 */
SemaphoreHandle_t xRecursiveMutex;
int recursiveCounter = 0;
/* 初始化递归互斥量 */
void vInitializeRecursiveMutex( void )
{
xRecursiveMutex = xSemaphoreCreateRecursiveMutex();
if( xRecursiveMutex == NULL )
{
configASSERT( 0 );
}
}
/* 递归函数示例 */
void vRecursiveFunction( int depth )
{
/* 获取递归互斥量 */
if( xSemaphoreTakeRecursive( xRecursiveMutex, pdMS_TO_TICKS( 1000 ) ) == pdTRUE )
{
/* 临界区:访问共享资源 */
recursiveCounter++;
if( depth > 0 )
{
/* 递归调用 - 同一任务可以多次获取互斥量 */
vRecursiveFunction( depth - 1 );
}
recursiveCounter--;
/* 释放递归互斥量 */
xSemaphoreGiveRecursive( xRecursiveMutex );
}
}
/* 使用递归函数的任务 */
void vRecursiveTask( void *pvParameters )
{
for( ;; )
{
/* 调用递归函数 */
vRecursiveFunction( 5 );
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
}
}
6. 优先级反转问题与解决方案
6.1 优先级反转现象
优先级反转是实时系统中的经典问题:
/* 优先级反转示例场景 */
void vHighPriorityTask( void *pvParameters ) /* 优先级:3 */
{
for( ;; )
{
/* 高优先级任务需要获取互斥量 */
if( xSemaphoreTake( xMutex, pdMS_TO_TICKS( 1000 ) ) == pdTRUE )
{
/* 临界区操作 */
criticalOperation();
xSemaphoreGive( xMutex );
}
vTaskDelay( pdMS_TO_TICKS( 100 ) );
}
}
void vMediumPriorityTask( void *pvParameters ) /* 优先级:2 */
{
for( ;; )
{
/* 中等优先级任务执行长时间操作 */
longRunningOperation();
vTaskDelay( pdMS_TO_TICKS( 50 ) );
}
}
void vLowPriorityTask( void *pvParameters ) /* 优先级:1 */
{
for( ;; )
{
/* 低优先级任务持有互斥量 */
if( xSemaphoreTake( xMutex, pdMS_TO_TICKS( 1000 ) ) == pdTRUE )
{
/* 长时间持有互斥量 */
longCriticalOperation();
xSemaphoreGive( xMutex );
}
vTaskDelay( pdMS_TO_TICKS( 200 ) );
}
}
问题分析:
-
低优先级任务获取互斥量
-
高优先级任务被阻塞等待互斥量
-
中等优先级任务抢占低优先级任务
-
高优先级任务被中等优先级任务间接阻塞
6.2 优先级继承解决方案
/* 优先级继承的实现机制 */
BaseType_t xTaskPriorityInherit( TaskHandle_t const pxMutexHolder )
{
TCB_t * const pxMutexHolderTCB = pxMutexHolder;
BaseType_t xReturn = pdFALSE;
if( pxMutexHolder != NULL )
{
/* 只有当互斥量持有者优先级低于当前任务时才继承 */
if( pxMutexHolderTCB->uxPriority < pxCurrentTCB->uxPriority )
{
/* 提升互斥量持有者的优先级 */
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 );
}
/* 如果持有者在就绪列表中,需要移动到新的优先级列表 */
if( listIS_CONTAINED_WITHIN( &( pxReadyTasksLists[ pxMutexHolderTCB->uxPriority ] ),
&( pxMutexHolderTCB->xStateListItem ) ) != pdFALSE )
{
if( uxListRemove( &( pxMutexHolderTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
portRESET_READY_PRIORITY( pxMutexHolderTCB->uxPriority, uxTopReadyPriority );
}
/* 继承优先级 */
pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
prvAddTaskToReadyList( pxMutexHolderTCB );
}
else
{
/* 任务不在就绪列表中,只更新优先级 */
pxMutexHolderTCB->uxPriority = pxCurrentTCB->uxPriority;
}
xReturn = pdTRUE;
}
}
return xReturn;
}
/* 优先级恢复 */
BaseType_t xTaskPriorityDisinherit( TaskHandle_t const pxMutexHolder )
{
TCB_t * const pxTCB = pxMutexHolder;
BaseType_t xReturn = pdFALSE;
if( pxMutexHolder != NULL )
{
/* 恢复原始优先级 */
if( pxTCB->uxPriority != pxTCB->uxBasePriority )
{
/* 从当前优先级列表中移除 */
if( uxListRemove( &( pxTCB->xStateListItem ) ) == ( UBaseType_t ) 0 )
{
portRESET_READY_PRIORITY( pxTCB->uxPriority, uxTopReadyPriority );
}
/* 恢复基础优先级 */
pxTCB->uxPriority = pxTCB->uxBasePriority;
/* 重新计算事件列表项的值 */
listSET_LIST_ITEM_VALUE( &( pxTCB->xEventListItem ),
( TickType_t ) configMAX_PRIORITIES - ( TickType_t ) pxTCB->uxPriority );
/* 添加到新的优先级列表 */
prvAddTaskToReadyList( pxTCB );
xReturn = pdTRUE;
}
}
return xReturn;
}
7. 性能分析与优化
7.1 信号量操作的时间复杂度
| 操作 | 时间复杂度 | 说明 |
|---|---|---|
| Give | O(1) | 直接操作计数器 |
| Take (成功) | O(1) | 直接操作计数器 |
| Take (阻塞) | O(log n) | 插入等待列表 |
| 优先级继承 | O(1) | 直接优先级操作 |
7.2 内存使用分析
/* 信号量内存占用分析 */
sizeof( Queue_t ) =
sizeof( int8_t * ) * 2 + /* pcHead, pcWriteTo */
sizeof( union ) + /* xQueue 或 xSemaphore */
sizeof( List_t ) * 2 + /* 等待列表 */
sizeof( UBaseType_t ) * 3 + /* 计数器和配置 */
sizeof( int8_t ) + /* 队列类型 */
/* 其他字段... */
/* 在32位系统上,大约64-80字节 */
7.3 性能优化建议
/* 1. 使用静态分配避免内存碎片 */
StaticSemaphore_t xSemaphoreBuffer;
SemaphoreHandle_t xSemaphore = xSemaphoreCreateBinaryStatic( &xSemaphoreBuffer );
/* 2. 合理设置超时时间 */
#define SEMAPHORE_TIMEOUT_MS 100
if( xSemaphoreTake( xSemaphore, pdMS_TO_TICKS( SEMAPHORE_TIMEOUT_MS ) ) == pdTRUE )
{
/* 处理逻辑 */
}
/* 3. 在中断中使用专用API */
void vISRHandler( void )
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
xSemaphoreGiveFromISR( xSemaphore, &xHigherPriorityTaskWoken );
portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
}
/* 4. 避免在临界区中长时间持有互斥量 */
void vOptimizedCriticalSection( void )
{
/* 准备工作在临界区外完成 */
prepareData();
if( xSemaphoreTake( xMutex, pdMS_TO_TICKS( 100 ) ) == pdTRUE )
{
/* 最小化临界区代码 */
quickCriticalOperation();
xSemaphoreGive( xMutex );
}
/* 后续处理在临界区外完成 */
postProcess();
}
8. 调试技巧与故障排除
8.1 常见问题诊断
/* 1. 死锁检测 */
void vDeadlockDetection( void )
{
/* 检查互斥量持有者 */
TaskHandle_t xHolder = xSemaphoreGetMutexHolder( xMutex );
if( xHolder != NULL )
{
/* 获取持有者信息 */
char *pcTaskName = pcTaskGetName( xHolder );
UBaseType_t uxPriority = uxTaskPriorityGet( xHolder );
printf( "Mutex held by: %s (Priority: %u)\n", pcTaskName, uxPriority );
}
}
/* 2. 信号量状态监控 */
void vSemaphoreMonitor( SemaphoreHandle_t xSemaphore )
{
UBaseType_t uxCount = uxSemaphoreGetCount( xSemaphore );
UBaseType_t uxWaiting = uxQueueGetNumberOfWaitingTasks( xSemaphore );
printf( "Semaphore count: %u, Waiting tasks: %u\n", uxCount, uxWaiting );
}
/* 3. 超时处理 */
BaseType_t xSafeResourceAccess( void )
{
if( xSemaphoreTake( xResourceMutex, pdMS_TO_TICKS( 1000 ) ) == pdTRUE )
{
/* 成功获取资源 */
accessResource();
xSemaphoreGive( xResourceMutex );
return pdTRUE;
}
else
{
/* 超时处理 */
logError( "Resource access timeout" );
return pdFALSE;
}
}
8.2 调试工具
/* 信号量使用统计 */
typedef struct
{
uint32_t ulTakeCount;
uint32_t ulGiveCount;
uint32_t ulTimeoutCount;
TickType_t xMaxWaitTime;
} SemaphoreStats_t;
SemaphoreStats_t xSemStats = { 0 };
/* 包装函数用于统计 */
BaseType_t xSemaphoreTakeWithStats( SemaphoreHandle_t xSemaphore, TickType_t xTimeout )
{
TickType_t xStartTime = xTaskGetTickCount();
BaseType_t xResult = xSemaphoreTake( xSemaphore, xTimeout );
TickType_t xWaitTime = xTaskGetTickCount() - xStartTime;
if( xResult == pdTRUE )
{
xSemStats.ulTakeCount++;
if( xWaitTime > xSemStats.xMaxWaitTime )
{
xSemStats.xMaxWaitTime = xWaitTime;
}
}
else
{
xSemStats.ulTimeoutCount++;
}
return xResult;
}
void vSemaphoreGiveWithStats( SemaphoreHandle_t xSemaphore )
{
xSemaphoreGive( xSemaphore );
xSemStats.ulGiveCount++;
}
9. 最佳实践
9.1 设计原则
-
选择合适的同步原语
-
任务通知:轻量级,1对1通信
-
二进制信号量:事件通知
-
计数信号量:资源计数
-
互斥量:资源保护
-
-
避免常见陷阱
-
不要在中断中使用阻塞API
-
避免优先级反转
-
防止死锁
-
-
性能考虑
-
最小化临界区
-
使用静态分配
-
合理设置超时
-
9.2 代码规范
/* 命名规范 */
SemaphoreHandle_t xDataReadySemaphore; /* 信号量 */
SemaphoreHandle_t xResourceMutex; /* 互斥量 */
SemaphoreHandle_t xRecursiveFileMutex; /* 递归互斥量 */
/* 错误处理 */
if( xSemaphoreTake( xMutex, pdMS_TO_TICKS( 1000 ) ) == pdTRUE )
{
/* 成功获取 */
processResource();
xSemaphoreGive( xMutex );
}
else
{
/* 超时处理 */
handleTimeout();
}
/* 资源清理 */
void vCleanupResources( void )
{
if( xMutex != NULL )
{
vSemaphoreDelete( xMutex );
xMutex = NULL;
}
}
10. 总结
FreeRTOS的信号量和互斥量系统展现了优秀的设计:
-
统一的实现基础:基于队列机制实现所有同步原语
-
丰富的功能支持:从简单的二进制信号量到复杂的递归互斥量
-
优先级继承:有效解决优先级反转问题
-
高效的性能:O(1)的基本操作,最小的内存占用
-
完善的调试支持:提供丰富的状态查询和错误检测机制
理解这些同步原语的实现原理和使用方法,是开发高质量FreeRTOS应用的关键。
下期预告
下一篇文章将深入探讨事件组机制,分析如何使用位操作实现高效的多任务同步,以及事件组在复杂同步场景中的应用技巧。
本文基于FreeRTOS V11.1.0源码分析,如有疑问或建议,欢迎交流讨论。
1296

被折叠的 条评论
为什么被折叠?



