转载自 https://blog.csdn.net/zhoutaopower/article/details/107387427

临界区的概念在任何的 SoC 都存在,比如,针对一个寄存器,基本操作为:读->改->写;在不带 OS 的系统下,普通代码希望对某个寄存器进行读->改->写,此刻,一个 IRQ 打断了这个操作,也同时对这个寄存器进行 读->改->写,中断返回,后,普通代码又继续进行,这样就会导致逻辑错误;

在带 OS 的情况下,不光是有 IRQ,而且存在任务切换,这样,同一个资源在 ISR 和不同任务之间修改,这造成了临界区;临界区的资源需要保护起来,临界区保护的不是代码,而是数据;

所以,在设计阶段尽早识别哪些是临界区,以及采取对应的策略,避免后续出现很难查的问题;

FreeRTOS 针对临界区资源,存在几种保护的方式:

1、taskENTER_CRITICAL() 和 taskEXIT_CRITICAL()

2、vTaskSuspendAll() 和 xTaskResumeAll()

3、Mutexes

4、Gatekeeper Tasks

接下来就看看他们的具体概念以及用法;

1、taskENTER_CRITICAL

这是个最强悍的临界区保护调用,它总是和 taskEXIT_CRITICAL 成对出现,即:

taskENTER_CRITICAL();
{
.............// 临界区
}
taskEXIT_CRITICAL();

为何称之为强悍,因为它直接屏蔽了中断,OS 调度靠中断,ISR 也靠中断;

也就是说,在这之间的对数据的操作,是绝对安全!

适用场景是,临界区可能存在于中断和任务中;

使用 taskENTER_CRITICAL 的时候,尽量保证这个临界区很短小,因为它暂停了所有的活动,来满足这段临界区,外部其他的任何响应,都无法阻止他;

它的实现是

注意:

1、在 ISR 中使用 taskENTER_CRITICAL_FROM_ISR() 和 taskEXIT_CRITICAL_FROM_ISR();

2、taskENTER_CRITICAL 和 taskEXIT_CRITICAL 必须成对出现;

taskENTER_CRITICAL 和 taskEXIT_CRITICAL  支持嵌套使用,因为里面维护了一个引用计数;

2、vTaskSuspendAll

上面那种关闭中断的方式,需要尽快退出临界区,以免引起中断延时处理,任务被延时处理;

FreeRTOS 还提供了一种挂起调度器的方式的临界区,它通过调用 vTaskSuspendAll 和 xTaskResumeAll 来建立临界区:

vTaskSuspendAll();
{
.............// 临界区
}
xTaskResumeAll();

这种方式和 taskENTER_CRITICAL 不一样的地方在于,它仅仅是挂起了调度器,而没有去关闭中断;换言之,资源争夺的场景中,它仅仅是防止了任务之间的资源争夺,中断照样可以直接响应;

所以,挂起调度器的方式,适用于,临界区位于任务与任务之间;既不用去延时中断,又可以做到临界区的安全;

3、Mutexes

3.1、Usage

互斥量是二值信号量的特殊形式 (它也是通过 Queue 实现),与二值信号量不同,互斥量用于控制多个任务之间共享资源的访问,也就是互锁;

不同于上面两种,互斥量不但开放了中断,同时也不挂起调度器;

使用互斥量,需要定义 configUSE_MUTEXES 为 1

用于互锁的互斥量可以充当保护资源的令牌。当一个任务希望访问某个资源时,它必须先获取令牌。当任务使用完资源后,必须还回令牌,以便其它任务可以访问同一资源。

互斥量和信号量使用相同的API函数,因此互斥量也允许指定一个阻塞时间。阻塞时间单位为系统节拍周期时间,数目表示获取互斥量无效时最多处于阻塞状态的系统节拍周期个数。

互斥量与二进制信号量最大的不同是:互斥量具有优先级继承机制。也就是说,如果一个互斥量(令牌)正在被一个低优先级任务使用,此时一个高优先级企图获取这个互斥量,高优先级任务会因为得不到互斥量而进入阻塞状态,正在使用互斥量的低优先级任务会临时将自己的优先级提升,提升后的优先级与与进入阻塞状态的高优先级任务相同。这个优先级提升的过程叫做优先级继承。这个机制用于确保高优先级任务进入阻塞状态的时间尽可能短,以及将已经出现的“优先级翻转”影响降低到最小。

在很多场合中,某个硬件资源只有一个,当低优先级任务占用该资源的时候,即便高优先级任务也只能乖乖的等待低优先级任务释放资源。这里高优先级任务无法运行而低优先级任务可以运行的现象称为“优先级翻转”。

为什么优先级继承能够降低优先级翻转的影响呢?举个例子,现在有任务A、任务B和任务C,三个任务的优先级顺序为任务C>任务B>任务A。任务A和任务C都要使用某一个硬件资源,并且当前任务A占有该资源。

先看没有优先级继承的情况:任务C也要使用该资源,但是此时任务A正在使用这个资源,因此任务C进入阻塞,此时三个任务的优先级顺序没有发生变化。在任务C进入阻塞之后,某硬件产生了一次中断,唤醒了一个事件,该事件可以解除任务B的阻塞状态。在中断结束后,因为任务B的优先级是大于任务A的,所以任务B抢占任务A的CPU权限。那么任务C的阻塞时间就至少为:中断处理时间+任务B的运行时间+任务A的运行时间。

再看有优先级继承的情况:任务C也要使用该资源,但是此时任务A正在使用这个资源,因此任务C进入阻塞,此时由于优先级A会继承任务C的优先级,三个任务的优先级顺序发生了变化,新的优先级顺序为:任务C=任务A>任务B。在任务C进入阻塞之后,某硬件产生了一次中断,唤醒了一个事件,该事件可以解除任务B的阻塞状态。在中断结束后,因为任务A的优先级临时被提高,大于任务B的优先级,所以任务A继续获得CPU权限。任务A完成后,处于高优先级的任务C会接管CPU。所以任务C的阻塞时间为:中断处理时间+任务A的运行时间。看,任务C的阻塞时间变小了,这就是优先级继承的优势。

优先级继承不能解决优先级反转,只能将这种情况的影响降低到最小。硬实时系统在一开始设计时就要避免优先级反转发生。

典型的,两个 Task A、Task B 都要访问同一个资源,他们通过互斥量来做互斥,

首先 A 获取到资源,进入临界区,

此刻 B 去获取资源,由于 A 还没用完资源,所有获取不到,进入阻塞;

A 执行完毕后,释放资源;

资源到位,B 解除阻塞,获取资源;

B 执行完毕,释放资源;

3.2、APIs

创建一个互斥量,使用 xSemaphoreCreateMutex

SemaphoreHandle_t xSemaphoreCreateMutex( void );

有一个返回值,如果成功创建,返回句柄,否则返回 NULL;

进入/ 退出 互斥量的临界区使用和信号量一样的接口 xSemaphoreTake 和 xSemaphoreGive,

注意:ISR 中使用带 _FromISR 版本的 API

Example:

static void prvNewPrintString( const char *pcString )
{
/* The mutex is created before the scheduler is started, so already exists by the
time this task executes. Attempt to take the mutex, blocking indefinitely to wait for the mutex if it is
not available straight away. The call to xSemaphoreTake() will only return when
the mutex has been successfully obtained, so there is no need to check the
function return value. If any other delay period was used then the code must
check that xSemaphoreTake() returns pdTRUE before accessing the shared resource
(which in this case is standard out). As noted earlier in this book, indefinite
time outs are not recommended for production code. */
xSemaphoreTake( xMutex, portMAX_DELAY );
{
/* The following line will only execute once the mutex has been successfully
obtained. Standard out can be accessed freely now as only one task can have
the mutex at any one time. */
printf( "%s", pcString );
fflush( stdout );
}
/* The mutex MUST be given back! */
xSemaphoreGive( xMutex );
}

FreeRTOS --(16)资源管理之临界区的更多相关文章

  1. freertos之资源管理学习

    OS下在对硬件外设资源操作.多任务的共享变量.任务和中断的共享变量操作时需要考虑资源的完整性和安全性. FREERTOS提供了临界区.调度器上锁.互斥量.优先级自动继承.创建守护任务的方法来改变最小优 ...

  2. FreeRTOS——资源管理

    1. 多任务系统存在一个潜在的风险:资源管理. 2. 基本临界区:taskENTER_CRITICAL() 与 taskEXIT_CRITICAL() 或 taskENTER_CRITICAL_FRO ...

  3. 记一次FreeRTOS错误配置导致无法进入临界区

    最近项目用到FreeRTOS,在实际调试中发现我自己的一段代码本来好用的(在无RTOS的情况下),但是当我在带RTOS的情况下把代码放到一个单独的任务中运行时我发现本来好用的代码莫名其妙的出现问题,有 ...

  4. Effective C++ 条款15、16 在资源管理类中提供对原始资源的访问||成对使用new 与 delete要采取相同形式

    1.在资源管理类中提供对原始资源的访问     前几个条款很棒,它们是对抗资源泄露的壁垒,但很多APIs直接指向 资源,这个时候,我们需要直接访问原始资源.     这里,有两种方法解决上述问题,我们 ...

  5. 鸟哥的Linux私房菜-----16、程序与资源管理

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...

  6. FreeRTOS相关转载-(朱工的专栏)

    FreeRTOS系列第1篇---为什么选择FreeRTOS? 1.为什么学习RTOS? 作为基于ARM7.Cortex-M3硬件开发的嵌入式工程师,我一直反对使用RTOS.不仅因为不恰当的使用RTOS ...

  7. STM32 使用 FreeRTOS过程记录

    资源:http://blog.csdn.net/zhzht19861011/article/category/6191478 资源:可以下载安富莱的STM32-V5开发版资料中的FreeRTOS教程, ...

  8. FreeRTOS随记

    任务函数原型: void ATaskFunction(void * pvParameters); 任务不允许从实现函数中返回.如果一个任务不再需要,可以用vTaskDelete()删除; 一个任务函数 ...

  9. freeRTOSConfig.h文件对FreeRTOS进行系统配置

    FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制.每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核.这个配置文件是针 ...

随机推荐

  1. Redis ZSet Type

    Redis有序集合的操作命令和对应的api如下: zadd [zset] sco 'value' JedisAPI:public Long zadd(final String key, final d ...

  2. 学习Solr(二)

    一.Solr概述 1.什么是Solr Solr 是Apache下的一个顶级开源项目,采用Java开发,它是基于Lucene的全文搜索服务器.Solr提供了比Lucene更为丰富的查询语言,同时实现了可 ...

  3. spring aop 源码解读之我见

    spring aop 都是动态代理,分为jdk代理和cglib代理.默认的情况下,如果类有实现了接口,使用jdk代理.如果没有实现接口,则使用cglib代理.在下面的代码中,我会标明对应的这段代码. ...

  4. html 常用标签及基本用法

    一个网页基本是由 结构(html) + 样式(css) + 脚本(js) 组成.学习的话 应该从最基本的标签开始, 结构清晰了, 再用css美化, 最后可以用脚本加上特效 块级 和 行类标签 特点: ...

  5. HTML5与HTML4区别简介

    移动互联网的快速发展,尤其是4G时代已经来临,加上微软在Windows 10中搭载了新的浏览器Edge取代了IE的地位,所以现在很多网站都开始抛弃IE朝着HTML5发展,PC端在不同浏览器之间的兼容性 ...

  6. 【Android开发】毛玻璃效果

    使用一:静态控件上使用 先附上自定义view-BlurringView public class BlurringView extends View { private int mDownsample ...

  7. 各种类型的Dialog

    下面是几种对话框的效果 图一: 图二: 图三: 图四: 图五: 图六: 图七: 图1效果:该效果是当按返回按钮时弹出一个提示,来确保无误操作,采用常见的对话框样式. 代码: 创建对话框方法dialog ...

  8. CCF201403-2窗口

    问题描述 在某图形操作系统中,有 N 个窗口,每个窗口都是一个两边与坐标轴分别平行的矩形区域.窗口的边界上的点也属于该窗口.窗口之间有层次的区别,在多于一个窗口重叠的区域里,只会显示位于顶层的窗口里的 ...

  9. JavaScript实现简单轮播图动画

    运行效果: 源代码: <!DOCTYPE html> <html lang="zh"> <head> <meta charset=&quo ...

  10. Java 8 学习记录

    Java 8 学习记录 官方文档 https://docs.oracle.com/javase/8/ https://docs.oracle.com/javase/8/docs/index.html ...