FreeRTOS互斥量

1.互斥量

我们在上一节中讲述了信号量,在使用信号量的时候会出现优先级“翻转”,怎么解决这问题呢,我们就引入互斥量来解决。

问题再现:

任务3需要得到任务1释放信号量之后才可以执行,导致任务2执行而最高级的任务3无法执行。

我们知道如果信号量只有0和1它也算是一个“互斥量”,但是这个互斥量有一些缺陷,比如“优先级翻转”问题。

互斥量的使用场景:

1、解决任务“优先级翻转”,怎么解呢,在互斥量函数内部,会有优先级继承,如果高优先级任务和低优先级任务共同使用同一个互斥量时,高优先级任务会将低优先级任务的优先等级暂时设定跟它一样,这样就保证了低优先级任务不会被阻塞,当低优先级任务释放互斥量后,高优先级任务会将低优先级任务优先级恢复,这样高优先级任务就不会一直阻塞。这是官方对这个创建互斥量函数的部分说明:

2、解决临界资源的使用问题

创建一个互斥量,在使用临界资源前进行Tack,在使用完成后进行Give。这个二进制信号量也是可以的。但是是否能够使用的权利要掌握在自己的手中,最好使用互斥量。

 

3、其他问题以后补充:······

2.互斥量的内部机制

与二进制信号量不同的是

1.它有优先级继承。

2.并且谁拿这个互斥量谁就得去释放,一对一的关系。

3.互斥量相关函数

只有创建不同,Tack(拿)和Give(释放,给)的函数是相同的。

3.1 创建

互斥量是一种特殊的二进制信号量。

使用互斥量时,先创建、然后去获得、释放它。使用句柄来表示一个互斥量。

创建互斥量的函数有2种:动态分配内存,静态分配内存,函数原型如下:

/* 创建一个互斥量,返回它的句柄。
 * 此函数内部会分配互斥量结构体 
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateMutex( void );

/* 创建一个互斥量,返回它的句柄。
 * 此函数无需动态分配内存,所以需要先有一个StaticSemaphore_t结构体,并传入它的指针
 * 返回值: 返回句柄,非NULL表示成功
 */
SemaphoreHandle_t xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer );

要想使用互斥量,需要在配置文件FreeRTOSConfig.h中定义:

#define configUSE_MUTEXES 1

3.2 其他函数

要注意的是,互斥量不能在ISR中使用。

各类操作函数,比如删除、give/take,跟一般是信号量是一样的。

/*
 * xSemaphore: 信号量句柄,你要删除哪个信号量, 互斥量也是一种信号量
 */
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );

/* 释放 */
BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore );


/* 获得 */
BaseType_t xSemaphoreTake(
                   SemaphoreHandle_t xSemaphore,
                   TickType_t xTicksToWait
               );

 

 4.递归锁

#4.1 死锁的概念

日常生活的死锁:我们只招有工作经验的人!我没有工作经验怎么办?那你就去找工作啊!

假设有2个互斥量M1、M2,2个任务A、B:

  • A获得了互斥量M1
  • B获得了互斥量M2
  • A还要获得互斥量M2才能运行,结果A阻塞
  • B还要获得互斥量M1才能运行,结果B阻塞
  • A、B都阻塞,再无法释放它们持有的互斥量
  • 死锁发生!

#4.2 自我死锁

假设这样的场景:

  • 任务A获得了互斥锁M
  • 它调用一个库函数
  • 库函数要去获取同一个互斥锁M,于是它阻塞:任务A休眠,等待任务A来释放互斥锁!
  • 死锁发生!

#4.3 函数

怎么解决这类问题?可以使用递归锁(Recursive Mutexes),它的特性如下:

  • 任务A获得递归锁M后,它还可以多次去获得这个锁
  • "take"了N次,要"give"N次,这个锁才会被释放

递归锁的函数根一般互斥量的函数名不一样,参数类型一样,列表如下:

递归锁一般互斥量
创建xSemaphoreCreateRecursiveMutexxSemaphoreCreateMutex
获得xSemaphoreTakeRecursivexSemaphoreTake
释放xSemaphoreGiveRecursivexSemaphoreGive

函数原型如下:

/* 创建一个递归锁,返回它的句柄。*

 * 此函数内部会分配互斥量结构体* 

 * 返回值: 返回句柄,非NULL表示成功*

 */

SemaphoreHandle_t xSemaphoreCreateRecursiveMutex( void );

*/ 释放 */

BaseType_t xSemaphoreGiveRecursive( SemaphoreHandle_t xSemaphore );

*/ 获得 */

BaseType_t xSemaphoreTakeRecursive(

         SemaphoreHandle_t xSemaphore,

         TickType_t xTicksToWait

        );

5.开发过程遇到的问题总结

待补充~~~ 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值