【FreeRTOS】08 互斥信号量、优先级反转问题

2023-05-16

本节继续讲freeRTOS的信号量,先讲一个与抢占式调度和信号量有关的经典问题——优先级反转,再讲互斥信号量。

1)什么是优先级反转

假设这样一种情况:

在一个具有抢占式调度的操作系统中,有三个任务A、B、C,它们优先级从高到低是A>B>C;任务A和C中都会需要获取信号量S。优先级反转产生的例子见下图:

初始0时刻,最低优先级的任务C正在运行,并且获取了信号量S;

之后,在1时刻,高优先级的任务A进入就绪态,由于它优先级最高,抢占了CPU,A开始运行;

到2时刻,任务A执行到需要获取信号量S时,发现信号量已经被占用了,所以被阻塞等待;任务A被阻塞后,C重新开始执行;

到3时刻,中等优先级的任务B进入了就绪态,由于任务B比任务C优先级高,则B抢占了CPU,B进入运行态;

只有当任务B执行完毕,任务C才能得到执行权;任务C释放信号量之后任务A才能执行。

这时,就出现了高优先级的任务A,因为信号量S(或者其他资源)的关系,必须等到中等优先级的任务B执行完了,才能执行的异常现象。这个现象就是优先级反转。如果任务B执行的时间很长,那么就会导致高优先级的A也需要等待很长时间。

优先级反转会造成低优先级的任务比高优先级的任务先执行,导致高优先级的任务实时性变差。

2)如何解决优先级反转

那么,如何解决优先级反转问题呢?一般有两种方法:优先级天花板和优先级继承。

优先级继承:当出现高优先级任务A需要等待低优先级任务C占用的资源时,将C的优先级提高到与A一样(有多个任务等待时,提高到等待它占用资源的任务的最高优先级)。

优先级天花板:当低优先级任务C占用资源时,把C的优先级提高到可能访问该资源的任务的最高优先级(称为该资源优先级天花板)。

这两种方法的核心思想,都是将占用信号量的任务的优先级临时提高,使得它不会被随意抢占;区别是优先级继承只在高优先级任务被阻塞时提高低优先级任务的优先级,而优先级天花板在低优先级任务获取资源时就提高了自己的优先级。

我们可以利用下面两个函数来修改、恢复任务的优先级:

UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask ); //获取任务的优先级

void vTaskPrioritySet( TaskHandle_t xTask, UBaseType_t uxNewPriority ); //修改任务的优先级

比如,为了避免优先级反转,我们用优先级天花板方法:C任务取得信号量时,把C任务的优先级提高到与A任务一样;释放信号量时,再把C任务的优先级修改为原来的即可。

3)互斥信号量

freeRTOS提供的互斥信号量,是一种特殊的二值信号量:

首先,它与二值信号量的功能差不多,可以实现资源的互斥访问(A获取了B就不能再获取,只能等到A释放之后其他任务才能获取);

其次,它自带了优先级继承功能,当互斥信号量已经被低优先级任务C获取,如果高优先级任务A需要等待这个信号量,会自动将任务C的优先级提高到与自己相同。

互斥信号量的功能使得它能避免优先级反转问题。

互斥信号量的创建使用下列两个函数:

SemaphoreHandle_t  xSemaphoreCreateMutex( void )

SemaphoreHandle_t  xSemaphoreCreateMutexStatic( StaticSemaphore_t *pxMutexBuffer )

释放信号量、获取信号量的函数与之前讲过的计数信号量、二值信号量相同,函数内部会自动判断是否是互斥信号量,如果是,它会执行优先级继承相关的调整。

释放信号量:

BaseType_t xSemaphoreGive( SemaphoreHandle_t xSemaphore ); //释放信号量

BaseType_t xSemaphoreGiveFromISR( SemaphoreHandle_t xSemaphore, signed BaseType_t *pxHigherPriorityTaskWoken); //从中断中释放信号量,后一个参数的返回值表示是否有高优先级的任务已经就绪,如果有,则需要进行一次任务切换

获取信号量:

BaseType_t xSemaphoreTake( SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait ); //获取信号量,后一个参数为阻塞的超时时间

BaseType_t xSemaphoreTakeFromISR(SemaphoreHandle_t  xSemaphore, BaseType_t *pxHigherPriorityTaskWoken); //在中断中获取信号量

4)编程试验

下面我们就以两个例子来演示优先级反转,以及使用互斥信号量避免优先级反转问题。

首先看优先级反转的试验:

我们定义三个任务:

DefaultTask优先级最低,Task02优先级中等,Task03优先级最高:

在Defaulttask任务中,在运行的0时刻,定义完二值信号量之后,立即占用信号量100ms,之后再释放:

 

任务Task02在50ms时,开始执行,它需要执行500ms,与信号量无关:

Task03在100ms时开始运行,它需要等待信号量:

运行结果如下图所示:

可以发现,起始时刻到50ms时,defaulttask占用了信号量之后,被Task02抢占了CPU;

到了100ms,Task03开始后运行,它优先级最高;但是它执行到等待信号量时,由于获取不到,自己进入了阻塞态;

之后由于最高优先级的任务是Task02,它一直占用了500ms的CPU,直到它释放CPU,defaulttask才得到执行;

Defaulttask释放信号量之后,Task03才得到执行。

可见由于信号量的影响,发生了优先级反转,最高优先级的任务A直到中等优先级的任务B执行完才能执行。

互斥信号量的优先级继承功能例子

接下来,我们把上述例子中的二值信号量换成互斥信号量,再来看看执行结果。

由于互斥信号量只有定义时与二值信号量不同,所以上例中的代码只需要修改信号量定义那一行:

然后再看执行结果:

可以看到,这个例子中,Task03执行到等待信号量时,defaulttask直接给出了信号量;

原本优先级最低的defaulttask并没有因为task02需要占用CPU而不能执行,说明它的优先级被临时提高了,起到了优先级继承的作用,互斥信号量解决优先级反转问题是有效的。

好了,本节的内容就到这里了。

如果觉得有用可以关注作者微信号“小白白学电子”,在公众号可以找到代码和资料下载地址:

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【FreeRTOS】08 互斥信号量、优先级反转问题 的相关文章

  • 基于HAL库的FREERTOS----------二.任务API函数

    任务API函数览概 CUBEMX对 做了API的封装 很多 的函数没有封装到位 可以用原函数调用 任务API函数分别介绍 1 uxTaskPriorityGet 此函数用来获取指定任务的优先级 要使用此函数的话宏 INCLUDE uxTas
  • FreeRTOS内核配置说明---FreeRTOS Kernel V10.2.1

    FreeRTOS内核是高度可定制的 使用配置文件FreeRTOSConfig h进行定制 每个FreeRTOS应用都必须包含这个头文件 用户根据实际应用来裁剪定制FreeRTOS内核 这个配置文件是针对用户程序的 而非内核 因此配置文件一般
  • FreeRTOS软件定时器创建、复位、开始和停止(备忘)

    目录 一 简介 1 1 开发环境 1 2 摘要 二 STM32CubeIDE配置 三 创建定时器 3 1 头文件声明 3 2 工程文件定义 3 3 创建定时器 3 4 开启 复位 和关闭定时器 四 定时器回调函数 一 简介 1 1 开发环境
  • FreeRTOS学习笔记(3、信号量、互斥量的使用)

    FreeRTOS学习笔记 3 信号量 互斥量的使用 前言 往期学习笔记链接 学习工程 信号量 semaphore 两种信号量的对比 信号量的使用 1 创建信号量 2 give 3 take 4 删除信号量 使用计数型信号量实现同步功能 使用
  • FreeRTOS学习(八) 延时函数

    声明及感谢 跟随正点原子资料学习 在此作为学习的记录和总结 环境 keil stm32f103 FreeRTOS延时函数有两个 分别是 vTaskDelay vTaskDelayUntil 1 vTaskDelay 任务相对延时 函数原型
  • Freertos中vTaskDelay()是怎么用的

    1 常见的使用场景 void vLED Task void pvParameters while 1 Heartbeat LED vTaskDelay 1000 portTICK RATE MS 说明 上面这段代码的意思是 led翻转后经过
  • freertos---软定时器

    一 软件定时器介绍 freeRTOS软件定时器的时基是基于系统时钟节拍实现的 可以创建很多个 在硬件定时器资源不充足的情况下非常有用 软件定时器一般用作周期性地执行函数 在创建软件定时器时指定软件定时器的回调函数 在回调函数中实现相应的功能
  • ZYNQ中FreeRTOS中使用定时器

    使用普通的Timer中断方式时 Timer中断可以正常运行 但是UDP通信进程无法启动 其中TimerIntrHandler是中断服务程序 打印程序运行时间与从BRAM中读取的数据 void SetupInterruptSystem XSc
  • FreeRTOS学习笔记<中断>

    中断概念 Cortex M的NVIC最多支持240个IRQ 中断请求 1个不可屏蔽中断 NMI 1个Systick 滴答定时器 定时器中断和多个系统异常 Cortex M处理器有多个用于管中断和异常的可编程寄存器 这些寄存器大多数都在 NV
  • FreeRTOS打印任务对CPU的占有率

    1 配置RTOS 1 打开RTOS Config Parameter 找到Run Time And Task States gathering related definitions 使能GENERATE RUN TIME STATS US
  • 基于HAL库的FREERTOS----------一.任务

    FreeROTS 就是一个免费的 RTOS 类系统 这里要注意 RTOS 不是指某一个确定的系统 而是指一类系统 比如 UCOS FreeRTOS RTX RT Thread 等这些都是 RTOS 类操作系统 FreeRTOS 是 RTOS
  • FreeRTOS+CubeMX系列第一篇——初识FreeRTOS

    文章目录 一 关于FreeRTOS 二 FreeRTOS的特点 三 如何在CubeMX上配置FreeRTOS 四 FreeRTOS文档资料 五 同系列博客 一 关于FreeRTOS 1 什么是FreeRTOS FreeRTOS是一个迷你的实
  • FreeRTOS_中断

    传送门 博客汇总帖 传送门 Cortex M3 中断 异常 传送门 Cortex M3笔记 基础 笔记内容参考 正点原子的FreeRTOS开发手册 cortex m3权威指南 Cortex M3和Cortex M4权威指南等 文中stm32
  • Error: L6218E: Undefined symbol vApplicationGetIdleTaskMemory (referred from tasks.o).

    我用的是F103ZET6的板子 移植成功后 编译出现两个错误是关于stm32f10x it c 里 void SVC Handler void void PendSV Handler void 两个函数的占用问题 随后编译出现以下两个问题
  • FreeRTOS笔记(一)简介

    这个笔记主要依据韦东山freertos快速入门系列记录 感谢韦东山老师的总结 什么是实时操作系统 操作系统是一个控制程序 负责协调分配计算资源和内存资源给不同的应用程序使用 并防止系统出现故障 操作系统通过一个调度算法和内存管理算法尽可能把
  • FreeRTOS死机原因

    1 中断回调函数中没有使用中断级API xxFromISR 函数 xSemaphoreGiveFromISR uart busy HighterTask 正确 xSemaphoreGive uart busy 错误 2 比configMAX
  • freeRTOS出现任务卡死的情况。

    最近在做一个产品二代升级的项目 代码是上一任工程师留下的 很多BUG 而且融合了HAL库和LL库 以及github上下载的GSM源码 很不好用 我这边是将2G模块换成了4G 且添加了单独的BLE模块 因此只在源码的基础上 去除2G和BLE代
  • FreeRTOS之系统配置

    1 FreeRTOS的系统配置文件为FreeRTOSConfig h 在此配置文件中可以完成FreeRTOS的裁剪和配置 在官方的demo中 每个工程都有一个该文件 2 先说一下 INCLUDE 开始的宏 使用 INCLUDE 开头的宏用来
  • FreeRTOS多任务调度器基础

    Cortex M4中SysTick调度器核心 Cortex M4中的中断管理 Cortex M4中影子栈指针 Cortex M4中SVC和PendSV异常 1 Cortex M4中SysTick调度器核心 systick每一次中断都会触发内
  • 当 Cortex-M3 出现硬故障时如何保留堆栈跟踪?

    使用以下设置 基于 Cortex M3 的 C gcc arm 交叉工具链 https launchpad net gcc arm embedded 使用 C 和 C FreeRtos 7 5 3 日食月神 Segger Jlink 与 J

随机推荐