引言
优先级反转是实时系统中的经典问题,它可能导致高优先级任务被低优先级任务阻塞,严重影响系统的实时性。FreeRTOS通过优先级继承机制巧妙地解决了这个问题。本文将深入分析FreeRTOS V11.1.0中优先级继承的实现原理和应用技巧。
1. 优先级反转问题
1.1 什么是优先级反转
优先级反转是指高优先级任务被低优先级任务间接阻塞的现象。典型场景:
任务优先级:TaskH (高) > TaskM (中) > TaskL (低) 时间线: 1. TaskL获得互斥量,开始执行 2. TaskH需要该互斥量,被阻塞 3. TaskM抢占TaskL,开始执行 4. TaskH被TaskM间接阻塞,优先级反转发生
1.2 优先级反转的危害
/* 优先级反转示例 */
SemaphoreHandle_t xMutex;
/* 低优先级任务 */
void vLowPriorityTask( void *pvParameters )
{
for( ;; )
{
/* 获取互斥量 */
if( xSemaphoreTake( xMutex, portMAX_DELAY ) == pdTRUE )
{
printf( "Low priority task: Got mutex\r\n" );
/* 长时间持有互斥量 */
vTaskDelay( pdMS_TO_TICKS( 1000 ) );
printf( "Low priority task: Releasing mutex\r\n" );
xSemaphoreGive( xMutex );
}
vTaskDelay( pdMS_TO_TICKS( 2000 ) );
}
}
/* 中优先级任务 */
void vMediumPriorityTask( void *pvParameters )
{
for( ;; )
{
printf( "Medium priority task: Running\r\n" );
/* CPU密集型工作,抢占低优先级任务 */
volatile uint32_t i;
for( i = 0; i < 10000000; i++ );
vTaskDelay( pdMS_TO_TICKS( 500 ) );
}
}
/* 高优先级任务 */
void vHighPriorityTask( void *pvParameters )
{
for( ;; )
{
vTaskDelay( pdMS_TO_TICKS( 3000 ) );
printf( "High priority task: Trying to get mutex\r\n" );
/* 尝试获取互斥量,可能被低优先级任务阻塞 */
if( xSemaphoreTake( xMutex, pdMS_TO_TICKS( 5000 ) ) == pdTRUE )
{
printf( "High priority task: Got mutex\r\n" );
/* 关键操作 */
vTaskDelay( pdMS_TO_TICKS( 100 ) );
xSemaphoreGive( xMutex );
printf( "High priority task: Released mutex\r\n" );
}
else
{
printf( "High priority task: Timeout waiting for mutex!\r\n" );
}
}
}
2. 优先级继承机制
2.1 优先级继承原理
当高优先级任务被互斥量阻塞时,持有互斥量的低优先级任务临时继承高优先级任务的优先级:
/* TCB中的优先级字段 */
typedef struct tskTaskControlBlock
{
UBaseType_t uxPriority; /* 当前优先级 */
UBaseType_t uxBasePriority; /* 基础优先级 */
UBaseType_t uxMutexesHeld; /* 持有的互斥量数量 */
/* ... 其他字段 ... */
} tskTCB;
/* 优先级继承的核心思想 */
/*
* 1. uxBasePriority:任务的原始优先级,不会改变
* 2. uxPriority:任务的当前优先级,可能因继承而提升
* 3. 当任务释放所有互斥量时,优先级恢复到uxBasePriority
*/
2.2 互斥量结构设计
/* 互斥量的内部结构(基于队列实现) */
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; /* 项目大小 */
volatile int8_t cRxLock; /* 接收锁 */
volatile int8_t cTxLock; /* 发送锁 */
#if ( ( configSUPPORT_STATIC_ALLOCATION == 1 ) && ( configSUPPORT_DYNAMIC_ALLOCATION == 1 ) )
uint8_t ucStaticallyAllocated; /* 静态分配标志 */
#endif
#if ( configUSE_QUEUE_SETS == 1 )
struct QueueDefinition *pxQueueSetContainer;
#endif
#if ( configUSE_TRACE_FACILITY == 1 )
UBaseType_t uxQueueNumber;
uint8_t ucQueueType;
#endif
} xQUEUE;
/* 信号量数据结构 */
typedef struct SemaphoreData
{
TaskHandle_t xMutexHolder; /* 互斥量持有者 */
UBaseType_t uxRecursiveCallCount; /* 递归调用计数 */
} SemaphoreData_t;
```#
# 3. 优先级继承实现机制
### 3.1 互斥量获取时的优先级继承
```c
/* 互斥量获取函数 */
BaseType_t xQueueSemaphoreTake( QueueHandle_t xQueue, TickType_t xTicksToWait )
{
BaseType_t xEntryTimeSet = pdFALSE;
TimeOut_t xTimeOut;
Queue_t * const pxQueue = xQueue;
for( ;; )
{
taskENTER_CRITICAL();
{
/* 检查互斥量是否可用 */
if( pxQueue->uxMessagesWaiting == ( UBaseType_t ) 0U )
{
/* 互斥量不可用,检查是否需要优先级继承 */
if( pxQueue->u.xSemaphore.xMutexHolder != NULL )
{
/* 实施优先级继承 */
if( pxQueue->u.xSemaphore.xMutexHolder->uxPriority < pxCurrentTCB->uxPriority )
{
vTaskPriorityInherit( pxQueue->u.xSemaphore.xMutexHolder );
}
}
}
else
{
/* 互斥量可用,获取成功 */
pxQueue->uxMessagesWaiting = 0U;
pxQueue->u.xSemaphore.xMutexHolder = pxCurrentTCB;
pxCurrentTCB->uxMutexesHeld++;
taskEXIT_CRITICAL();
return pdPASS;
}
}
taskEXIT_CRITICAL();
/* 互斥量不可用,需要等待 */
if( xTicksToWait == ( TickType_t ) 0 )
{
return errQUEUE_EMPTY;
}
/* 设置超时并阻塞等待 */
if( xEntryTimeSet == pdFALSE )
{
vTaskInternalSetTimeOutState( &xTimeOut );
xEntryTimeSet = pdTRUE;
}
vTaskSuspendAll();
prvLockQueue( pxQueue );
if( xTaskCheckForTimeOut( &xTimeOut, &xTicksToWait ) == pdFALSE )
{
if( prvIsQueueEmpty( pxQueue ) != pdFALSE )
{
/*

最低0.47元/天 解锁文章
2731

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



