【FreeRTOS】06 临界段的保护——关中断和关调度
本节来讲一讲FreeRTOS如何保护临界段,先讲临界段的概念,再讲保护临界段的方法。
1)临界段的概念
简单来讲,临界段是一段执行时不允许被中断(或其他任务)打断的代码;如果被打断,就有可能运行出错。
举个例子:
假设我们有一个任务Task1需要向队列FIFO中写入数据,中断服务函数TaskISR1也需要向队列FIFO中写入数据;我们知道,FIFO的写或者读需要依次执行:写入/读出数据、更新读/写指针。
如果Task1在向FIFO中写入数据时,执行完写入数据,但还没有更新写指针,此时中断来了,TaskISR1开始运行,它也需要向FIFO中写入,而由于Task1运行时还没有更新写指针,则TaskISR写入的数据会把Task1刚刚写入的数据覆盖,然后更新写指针;这就出现了一次丢失数据的错误。
当然错误还不只如此,中断服务程序TaskISR1运行完毕后,回到Task1继续运行,它会接着被打断的位置向后执行,更新写指针;这样就相当于没有写入数据,但又更新了一次写指针。
像这个例子中的FIFO写入数据、读出数据的代码段,就是临界段;它的读写数据和更新读写指针,两个操作之间不能被打断,否则就会可能出错。
用户代码中用于任务和中断间通信的变量、不可重入函数,操作系统的某些底层代码,都有可能是临界段。如果不保护好临界段,代码就会出现各种难以排查、难以复现的bug。
而最简单的保护临界段的方法,就是关闭中断,以及关闭任务调度。也就是暂时禁止中断和其他任务执行,等到临界段执行完毕后再恢复。具体使用时,如果有可能被中断打断,则关闭中断,如果有可能被高优先级的任务打断,则可以关闭任务调度。
注意!这种“关闭”是临时的,执行完临界段之后,必须要恢复允许中断和任务调度的状态。否则,中断和其他任务就无法运行了。
此外,由于执行临界段时,关闭了任务或任务调度,系统无法响应其他的实时事件,会降低系统的实时性;所以我们编写代码时,需要准确识别临界段,使得临界段尽量短,即只把需要保护的最小的一段代码保护起来即可。
2)freeRTOS中的临界段保护
freeRTOS系统中定义了保护临界段的宏:
在任务中,taskENTER_CRITICAL(),用于进入临界段前保护;taskEXIT_CRITICAL(),用于临界段执行完之后,退出保护。
查看代码调用情况,可以看到它们最后是由下述两个函数实现:
这其中除了开/关中断的代码,还有一个嵌套计数,为的是记录进入了几层“关中断”中,这样在退出临界区时,就不会错误地提前退出了。
其中的开/关中断的操作,是用嵌入的汇编代码实现的,如下所示,关闭中断时,只关闭了优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断:
由于freeRTOS提供的进入临界段的代码,本质上是关闭中断,而一旦关闭中断,则freeRTOS的任务切换功能也被禁止了,所以,它同时能够保护中断和任务间的临界段冲突。
另外,如果想要在中断服务程序中进入临界段,要使用另一套函数来保护临界段:taskENTER_CRITICAL_FROM_ISR(),用于进入临界段前保护;taskEXIT_CRITICAL_FROM_ISR( x )用于临界段执行完之后,退出保护。代码的实现是类似的,感兴趣的可以自行阅读代码。
3)保护临界段的测试实例
我们以一个例子来试验freeRTOS临界段的保护功能:
首先来看不保护临界段的情况。
建立任务,我们把defaultTask任务优先级设置为普通,Task02任务的优先级设置为高,这样,Task02就可以打断defaultTask的执行:
编写一个具有临界段属性的函数,这里我们用串口来实现,就是普通地往串口寄存器中写入数据:
编写两个任务内部执行的功能,都是通过访问串口的临界段函数,打印输出;不同的是高优先级的Task2第一次运行时延迟了5ms,这样可以实现defaultTask任务先执行5ms,之后Task02打断它执行:
上述程序运行结果如下:
可以看到,串口打印的输出,DefaultTask任务首次运行时,打印了前6个字符:Defaul后,被Task02打断,进入了Task02任务的打印功能;Task02打印完毕后,才继续打印DefaultTask未完成的打印字符:tTask is running。
所以,如果临界段Uart1Send函数不加保护,它的打印输出有可能被打断,输出不正确的字符串。
如下所示修改defaultTask的代码,加入临界段保护和退出的语句:
再次运行上述程序,可以看到输出如下,输出了正确的字符串:
所以,临界段保护代码功能是有效的。
4)关闭任务调度
上述的freeRTOS定义的临界区保护的操作,是直接关闭中断;而实际上,有时有的临界段中断里不访问,只用保护不被其他任务打断即可;这时也可以临时关闭任务调度功能,来实现临界段的保护。
freeRTOS系统中定义了关闭任务调度和开启任务调度的函数:
vTaskSuspendAll()、xTaskResumeAll()
这两个函数也需要成对使用,关闭任务调度后,然后执行临界段,最后一定要恢复到开启调度的状态。
而且,在关闭调度后,不能再使用任何会引起任务切换的函数,如之前讲到的延时vTaskDelayUntil、vTaskDelay,以及以后会讲到的信号量、消息队列等函数;直到重新开启任务调度。
在3)中的例子,临界段访问的冲突是不同任务间引起的,我们也可以通过临时关闭任务调度来实现临界段的保护,如下所示:
这个程序的执行结果,和使用taskENTER_CRITICAL()、taskEXIT_CRITICAL()保护临界段是一样的。大家可以自行测试一下。
好了,本节的内容就到这里了。
如果觉得有用可以关注作者微信号“小白白学电子”,在公众号可以找到代码和资料下载地址:
【FreeRTOS】06 临界段的保护——关中断和关调度相关推荐
- FreeRTOS内核实现03:临界段的保护
目录 1. 临界段概述 1.1 什么是临界段 1.2 临界段何时会被打断 2. 关中断操作 2.1 不带中断保护 2.2 带中断保护 3. 开中断操作 4. 进入临界段操作 4.1 不带中断保护 4. ...
- FreeRTOS临界段的保护
什么是临界段 临界段用一句话概括就是一段在执行的时候不能被中断的代码段.在 FreeRTOS 里面, 这个临界段最常出现的就是对全局变量的操作,全局变量就好像是一个枪把子,谁都可以 对他开枪,但是我开 ...
- 从0到1写RT-Thread内核——临界段的保护
临界段就是一段在执行的时候不能被中断的代码段,在RT-Thread里,临界段最常出现的就是对全局变量的操作(类似Linux下的锁).RT-Thread对临界段的保护是直接把中断全部关了,NMI FAU ...
- FreeRTOS中断配置与临界段
Cortex-M中断 中断是指计算机运行过程中,出现某些意外情况需主机干预时,机器能自动停止正在运行的程序并转入处理新情况的程序(中断服务程序),处理完毕后又返回原被暂停的程序继续运行.Cortex- ...
- FreeRTOS 临界段和开关中断
以下转载自安富莱电子: http://forum.armfly.com/forum.php 临界段 代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断.为确保临界段代码 的执行不被 ...
- FreeRTOS内核详解(1) —— 临界段保护原理
什么是临界段 临界段用一句话概括就是一段在执行的时候不能被中断的代码段. 在 FreeRTOS 里面,这个临界段最常出现的就是对全局变量的操作,由于不同任务间可以切换运行,当一个任务在访问某个全局变量 ...
- FreeRTOS源码分析与应用开发01:中断配置与临界段
目录 1. 异常与中断的基本概念 1.1 异常分类 1.2 中断概述 1.2.1 中断处理宜短暂 1.2.2 临界段影响中断实时性 1.3 中断硬件基础 1.3.1 外设 1.3.2 中断控制器 1. ...
- freertos临界段保护
freertos临界段保护 中断的基础知识 cortex-m里面开中断.关中断指令 关中断和开中断 进入临界段和退出临界段 中断的基础知识 嵌套: 嵌套向量中断控制器 NVIC(Nested Vect ...
- FreeRTOS — 临界段和开关中断
以下内容转载自安富莱电子:http://forum.armfly.com/forum.php 1.临界段 代码的临界段也称为临界区,一旦这部分代码开始执行,则不允许任何中断打断.为确保临界段代码的执行 ...
最新文章
- bugku 杂项 就五层你能解开吗_你能解开这个和数字有关的逻辑解谜游戏吗? | 每日一考...
- oracle 新建路径,Linux环境安装Oracle11g(三)——用户、路径创建及配置环境变量
- Linux打印指定的行范围
- SAP BTP 平台 CloudFoundry 环境入门级别的介绍
- 看阿里云如何用云上技术创新,帮助哈啰单车实现智能数据收治
- 什么是Apache Spark?这篇文章带你从零基础学起
- oracle下的inventory文件夹,oracle INVENTORY 详解
- set get java_JAVA中关于set()和get()方法的理解及使用
- 011-你觉得自动化测试有什么意义,都需要做些什么
- python list去重函数_Python基础中的集合,函数——06
- cmos和ttl_TTL和CMOS的比较
- linux系统notebook,RedNotebook——Linux环境桌面日记本
- LICEcap--小巧而精致的GIF录屏工具
- 利用Python网络爬虫抓取韩寒博客推荐第一篇(urllib的简单使用与Beautifulsoup实战,i/o编程)
- 10大程序员必逛网站,良心推荐,建议收藏!
- 字节、腾讯、金山wps、跟谁学、百度 go工程师面试题集锦
- 三.MFC DLL窗口的创建和注入显示
- 计算机导论部分知识整理
- 系统架构演变:SOA、微服务架构的区别和联系
- 初级中学理化生实验室建设与配备标准
热门文章
- 为PostgreSQL配置work_mem
- 2021年中国数据安全行业发展现状及未来发展前景分析:数据安全市场快速增长[图]
- PostgreSQL的ON CONFLICT
- 1年时间强势进阶,百度财报公布好看视频成长秘密
- Python Opencv 通过轨迹(跟踪)栏实现更改整张图像的背景颜色(末尾有一个小训练——是将所学得的图像颜色修改应用为画板一般的刷新)
- 8张图,看懂数据驱动业务的六个层次
- 在 EXCEL 中,“插入已剪切单元格”的快捷键
- 进制之间的快速转换法:8421码及原码反码补码之间的相互转换关系
- 2019, XII Samara Regional Intercollegiate Programming Contest 解题报告
- iPhone 游戏 Dungeon Hunter2 地牢猎手 今日通关