学习FreeRTOS(六) - 信号量

信号量其实就是队列的一种应用,信号量的各种操作都是在队列的基础上建立起来的。那么既然是在队列的基础上建立的,信号量一定具有和队列相同的属性。因此信号量也是为任务和任务、任务和中断之间通信做准备的,但是信号量一般用来进行资源管理和任务同步。因为信号量是一种共享资源,当它被创建之后,系统中所有任务和中断都能对信号量进行访问。同时也可以进行任务同步,即在一个任务(或中断)中告诉另一个任务它所等待的事件发生了,等到发生任务调度的时候,再切换到相应任务中,执行该事件发生的相关处理。FreeRTOS中的信号量有二值信号量、互斥信号量、计数信号量、递归互斥信号量,我们一般用二值信号量和计数信号量。

二值信号量

#define semSEMAPHORE_QUEUE_ITEM_LENGTH                              ( ( uint8_t ) 0U )

#define xSemaphoreCreateBinary() xQueueGenericCreate( ( UBaseType_t ) 1, semSEMAPHORE_QUEUE_ITEM_LENGTH, queueQUEUE_TYPE_BINARY_SEMAPHORE )

#define semGIVE_BLOCK_TIME                                                               ( ( TickType_t ) 0U )

#define xSemaphoreGive( xSemaphore )                xQueueGenericSend( ( QueueHandle_t ) ( xSemaphore ), NULL, semGIVE_BLOCK_TIME, queueSEND_TO_BACK )

#define xSemaphoreTake( xSemaphore, xBlockTime )                      xQueueGenericReceive( ( QueueHandle_t ) ( xSemaphore ), NULL, ( xBlockTime ), pdFALSE )

其底层实现函数都是和我们之前消息队列的一样。

计数信号量:

之前二值信号量队列的长度uxlength为1, 现在计数信号量可以自己配置。

QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount )

QueueHandle_t xQueueCreateCountingSemaphore( const UBaseType_t uxMaxCount, const UBaseType_t uxInitialCount )

{

    QueueHandle_t xHandle;

    configASSERT( uxMaxCount != 0 );

    configASSERT( uxInitialCount <= uxMaxCount );

    // 申请队列, 深度由第一个参数决定

    // item size 也是为 0

    xHandle = xQueueGenericCreate( uxMaxCount,

        queueSEMAPHORE_QUEUE_ITEM_LENGTH,

        queueQUEUE_TYPE_COUNTING_SEMAPHORE );

    if( xHandle != NULL )

    {

        // 初始化信号量计数值

        ( ( Queue_t * ) xHandle )->uxMessagesWaiting = uxInitialCount;

    }

    return xHandle;

}

互斥量(mutex)

互斥量用于互锁的互斥量可以充当保护资源的令牌,当一个任务希望访问某个资源时,它必须先获取令牌。当任务使用完资源后,必须还回令牌,以便其它任务可以访问该资源。是不是很熟悉,在我们的二值信号量里面也是一样的,用于保护临界资源,保证多任务的访问井然有序。当任务获取到信号量的时候才能开始使用被保护的资源,使用完就释放信号量,下一个任务才能获取到信号量从而可用使用被保护的资源。但是信号量会导致的另一个潜在问题,那就是任务优先级翻转。而 FreeRTOS 提供的互斥量可以通过优先级继承算法,可以降低优先级翻转问题产生的影响,所以,用于临界资源的保护一般建议使用互斥量。

优先级反转:

图中,三个任务t1、t2、t3的优先级分别是高、中、低。低优先级任务t3通过获取信号量来获取一些资源。t3运行一段时间后,t1就绪抢占t3得到运行,一段时间后t1需要相同信号量保护的资源时,t1由于获取不到信号量而阻塞。被t1抢占的t3得到继续运行。接着低优先级任务t3受到中优先级任务t2的抢占,t2的抢占导致t3迟迟无法释放信号量,这种情况可能会持续存在,最终导致高优先级任务t1无限期阻塞。在这种情况下,优先级发生了翻转,任务t2总是先于任务t1运行

2. 优先级反转解决办法

通过上图可知,只要t3不被中优先级任务抢占,尽快释放信号量就行了,所以在t1阻塞期间需要给t3一个足够高的优先级。避免优先级反转有优先级天花板优先级继承两种办法。

优先级天花板是当任务申请某资源时, 把该任务的优先级提升到可访问这个资源的所有任务中的最高优先级, 这个优先级称为该资源的优先级天花板。

优先级继承是当任务t1 申请共享资源S 时, 如果S正在被任务t3 使用,通过比较任务t3 与t1的优先级,如发现任务t3 的优先级小于t1的优先级, 则将任务t3的优先级提升到t1的优先级,等t3 释放资源S 后,再恢复任务t3 的原优先级。

互斥量的优先继承机制只能在任务中起作用,不能在中断中使用。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值