FreeRTOS --(16)资源管理之临界区
转载自 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)资源管理之临界区的更多相关文章
- freertos之资源管理学习
OS下在对硬件外设资源操作.多任务的共享变量.任务和中断的共享变量操作时需要考虑资源的完整性和安全性. FREERTOS提供了临界区.调度器上锁.互斥量.优先级自动继承.创建守护任务的方法来改变最小优 ...
- FreeRTOS——资源管理
1. 多任务系统存在一个潜在的风险:资源管理. 2. 基本临界区:taskENTER_CRITICAL() 与 taskEXIT_CRITICAL() 或 taskENTER_CRITICAL_FRO ...
- 记一次FreeRTOS错误配置导致无法进入临界区
最近项目用到FreeRTOS,在实际调试中发现我自己的一段代码本来好用的(在无RTOS的情况下),但是当我在带RTOS的情况下把代码放到一个单独的任务中运行时我发现本来好用的代码莫名其妙的出现问题,有 ...
- Effective C++ 条款15、16 在资源管理类中提供对原始资源的访问||成对使用new 与 delete要采取相同形式
1.在资源管理类中提供对原始资源的访问 前几个条款很棒,它们是对抗资源泄露的壁垒,但很多APIs直接指向 资源,这个时候,我们需要直接访问原始资源. 这里,有两种方法解决上述问题,我们 ...
- 鸟哥的Linux私房菜-----16、程序与资源管理
watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/ ...
- FreeRTOS相关转载-(朱工的专栏)
FreeRTOS系列第1篇---为什么选择FreeRTOS? 1.为什么学习RTOS? 作为基于ARM7.Cortex-M3硬件开发的嵌入式工程师,我一直反对使用RTOS.不仅因为不恰当的使用RTOS ...
- STM32 使用 FreeRTOS过程记录
资源:http://blog.csdn.net/zhzht19861011/article/category/6191478 资源:可以下载安富莱的STM32-V5开发版资料中的FreeRTOS教程, ...
- FreeRTOS随记
任务函数原型: void ATaskFunction(void * pvParameters); 任务不允许从实现函数中返回.如果一个任务不再需要,可以用vTaskDelete()删除; 一个任务函数 ...
- freeRTOSConfig.h文件对FreeRTOS进行系统配置
FreeRTOS内核是高度可定制的,使用配置文件FreeRTOSConfig.h进行定制.每个FreeRTOS应用都必须包含这个头文件,用户根据实际应用来裁剪定制FreeRTOS内核.这个配置文件是针 ...
随机推荐
- class文件和java文件区别
- kafka分布式的情况下,如何保证消息的顺序?
作者:可期链接:https://www.zhihu.com/question/266390197/answer/772404605来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注 ...
- springboot项目配置类
一.在springboot项目中,如果不进行配置,直接访问静态页面是无法访问的,需要进行配置,springboot舍弃了XML文件的配置方式,这里我们采用开发配置类的方式.新建MvcConfig类,加 ...
- Redis 集群会有写操作丢失吗?为什么?
Redis 并不能保证数据的强一致性,这意味这在实际中集群在特定的条件下可能会丢失写操作.
- 线程池提交任务的两种方式:execute与submit的区别
Java中的线程池在进行任务提交时,有两种方式:execute和submit方法. 一.execute和submit的区别 execute只能提交Runnable类型的任务,无返回值.submit既可 ...
- 学习heartbeat-01简介
1.Heartbeat介绍 Heartbeat 是一个基于Linux开源的,被广泛使用的高可用集群系统,自1999年开始到现在,发布了众多版本,是目前开源Linux-HA项目最成功的一个例子,在行业内 ...
- Unsafe Rust 能做什么
在不安全的 Rust 中唯一不同的是,你可以: 对原始指针进行解引用 调用"不安全"的函数(包括 C 函数.编译器的内建指令和原始分配器. 实现"不安全"的特性 ...
- 4_ 比例控制器_燃烧卡路里(2)_Matlab/Simulink_Proportional Control
- 使用Google Closure Compiler高级压缩Javascript代码
背景 前端开发中,特别是移动端,Javascript代码压缩已经成为上线必备条件. 如今主流的Js代码压缩工具主要有: 1)Uglify http://lisperator.net/uglifyjs/ ...
- 用Weex开发的V2EX三端app,附探坑总结
项目地址 git传送门(内附项目预览) Weex环境配置 npm install -g weex npm install -g weexpack # weex客户端的cli npm install - ...