FreeRTOS连载10:信号量与互斥量 - 二进制信号量、计数信号量、递归互斥量的实现

引言

信号量和互斥量是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 ) );
    }
}

问题分析

  1. 低优先级任务获取互斥量

  2. 高优先级任务被阻塞等待互斥量

  3. 中等优先级任务抢占低优先级任务

  4. 高优先级任务被中等优先级任务间接阻塞

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 信号量操作的时间复杂度

操作时间复杂度说明
GiveO(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对1通信

    • 二进制信号量:事件通知

    • 计数信号量:资源计数

    • 互斥量:资源保护

  2. 避免常见陷阱

    • 不要在中断中使用阻塞API

    • 避免优先级反转

    • 防止死锁

  3. 性能考虑

    • 最小化临界区

    • 使用静态分配

    • 合理设置超时

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的信号量和互斥量系统展现了优秀的设计:

  1. 统一的实现基础:基于队列机制实现所有同步原语

  2. 丰富的功能支持:从简单的二进制信号量到复杂的递归互斥量

  3. 优先级继承:有效解决优先级反转问题

  4. 高效的性能:O(1)的基本操作,最小的内存占用

  5. 完善的调试支持:提供丰富的状态查询和错误检测机制

理解这些同步原语的实现原理和使用方法,是开发高质量FreeRTOS应用的关键。

下期预告

下一篇文章将深入探讨事件组机制,分析如何使用位操作实现高效的多任务同步,以及事件组在复杂同步场景中的应用技巧。


本文基于FreeRTOS V11.1.0源码分析,如有疑问或建议,欢迎交流讨论。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VehSwHwDeveloper

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值