FreeRTOS基础(七):临界段代码保护及调度器挂起与恢复

2024-06-02 13:52

本文主要是介绍FreeRTOS基础(七):临界段代码保护及调度器挂起与恢复,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

      上一篇博客我们详细介绍了FreeRTOS是怎么管理中断的,其实,从本质上来讲就是将就是利用的BASEPRI这个寄存器,来屏蔽优先级低于某一个阈值的中断,当设置为0的时候,就是打开所有中断,所有中断都可以响应。这样就实现了对所有中断的管理!(中断的管理就是关闭某一个范围的中断和打开中断)。这一篇博客,我们介绍一个另外一个重要的概念,这在实际开发也有非常多的应用。

目录

一、临界段代码保护简介(熟悉)

1.1 什么是临界段代码

1.2 适用场合

1.3 什么可以打断当前程序的运行(打断临界段)?

1.3.1 中断

1.3.2  任务调度

1.4 如何避免打断临界段?

1.5 临界段代码保护API函数介绍

1.5.1 调用格式示例

​1.5.2 特点

1.5.3 总结 

二、任务调度器的挂起和恢复

2.1 概念

2.2 任务调度器的挂起和恢复API函数

2.2.1 任务调度器挂起函数

2.2.2 任务调度器恢复函数

2.3 与使用关闭中断和打开中断实现临界段代码保护的区别

2.4 挂起和恢复任务调度器适用场合

2.5 使用格式示例

2.6 任务挂起与恢复内部实现(了解)


一、临界段代码保护简介(熟悉)

1.1 什么是临界段代码

         临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段。

1.2 适用场合

1.3 什么可以打断当前程序的运行(打断临界段)?

1.3.1 中断

        当中断发生的时候,当前运行的程序就会被暂停,转而去执行中断。

1.3.2  任务调度

       当前任务正在运行,出现一个更高优先级的任务,那么当前运行的程序就会被阻塞住。

1.4 如何避免打断临界段?

       通过上面,我们知道打断临界段的原因有哪些,那么我们就可以对症下药了,解决问题了。

      首先,关闭中断,则中断就不会打断我的运行,其次,任务调度也打断不了我,因为:PendSV是实现任务调度的一个内核中断,并且这个中断的优先级被设置成最低15,这里的关闭中断指的是:在管理的中断优先级范围内(FreeRTOS所能管理的最高中断)的中断都不会响应,那么自然优先级最低的PendSV中断也会被关闭,那么就无法进行任务切换调度,也就无法打断当前程序的运行!

1.5 临界段代码保护API函数介绍

        通过上面的分析,我们就不谋而合了,FreeRTOS 在进入临界段代码的时候需要关闭中断(管理范围内的中断),当处理完临界段代码以后再打开中断,进行正常的中断响应和任务调度。这就是临界段代码保护的方法!

     中断级的临界区函数会返回之前中断屏蔽寄存器的值,我们需要用一个变量接收,保存下来,然后关闭中断,退出临界区时将之前的中断屏蔽寄存器的值写回去。

1.5.1 调用格式示例

1.5.2 特点

1、成对使用。

2、支持嵌套。

3、尽量保持临界段耗时短。因为:在临界区屏蔽了中断,并且也不会发生任务调度了,中断一般是紧急的事,任务调度是可以满足实时性的,如果时间太长,可想而知,会带来什么后果!因此需要注意临界区代码的执行时间不宜过长,否则可能导致系统中断响应的延迟。

1.5.3 总结 

        临界段代码保护是直接屏蔽了中断(管理范围内),系统任务调度靠中断,ISR也靠中断,因此它的影响还是非常大的!!!

二、任务调度器的挂起和恢复

2.1 概念

        挂起就是暂停的意思,任务调度器挂起就是:任务不能再进行切换/调度,恢复就是任务调度器可以重新进行任务的切换。仅仅针对的是任务调度器,就是是否可以发生任务切换!

2.2 任务调度器的挂起和恢复API函数

2.2.1 任务调度器挂起函数

  • vTaskSuspendAll() 函数用于暂停任务调度器。调用这个函数后,任务切换将不会发生,系统会保持当前正在运行的任务。挂起调度器不会关闭中断,中断服务程序(ISR)仍然可以运行。
  • 这个函数通常用于临界区代码保护,确保一段代码在执行过程中不会被任务切换打断。

2.2.2 任务调度器恢复函数

  • xTaskResumeAll() 函数用于恢复任务调度器。恢复后,如果有较高优先级的任务被挂起期间解锁,那么这些任务将会立即执行。如果没有优先级更高的任务,当前任务将继续执行。
  • 在恢复任务调度时,系统会检查任务是否需要进行上下文切换,以确保高优先级任务能及时执行。

2.3 与使用关闭中断和打开中断实现临界段代码保护的区别

FreeRTOS提供了两种主要的临界段代码保护方法:

关闭和打开中断(portENTER_CRITICAL() 和 portEXIT_CRITICAL()):

  • portENTER_CRITICAL() 函数关闭中断,确保在临界区代码执行期间不会被管理范围内的中断打断。也不会发生任务的切换。
  • portEXIT_CRITICAL() 函数重新打开中断,允许系统恢复正常中断处理。
  • 优点:
    • 提供了最高级别的临界区保护,因为它完全阻止了中断
    • 适用于非常短且时间敏感的代码段
  • 缺点:
    • 关闭中断会影响整个系统的中断响应时间,可能会导致高优先级中断的延迟处理。
    • 不适用于长时间执行的代码,因为这会严重影响系统的实时性。

挂起和恢复任务调度器(vTaskSuspendAll 和 xTaskResumeAll):

  • vTaskSuspendAll() 暂停任务调度,但不会影响中断。这意味着ISR仍然可以执行,且ISR可以发起上下文切换(如果在ISR中调用了Yield函数)
  • xTaskResumeAll() 恢复任务调度,并在必要时进行上下文切换。
  • 它仅仅是防止了任务之间的资源争夺,中断照样可以直接响应;中断可以抢占当前任务的资源,但是其他任务无法抢占当前任务资源
  • 优点:
    • 保持中断响应能力,因为中断不会被禁用
    • 适用于需要保护不被任务切换打断的长时间执行代码,但又不需要完全禁止中断的场景。
  • 缺点:
    • 不适用于极端时间敏感的代码保护,因为ISR仍然可以打断执行。
    • 任务调度恢复时需要检查并可能进行任务切换,增加了一些开销。

   总结一下就是:利用任务调度器的挂起和恢复实现的临界段代码保护只是不会发生任务的切换,但是中断并未关闭,在临界区,中断依然可以响应,然而,利用关中断和开中断实现的临界段代码,它直接关闭了管理范围内的中断,任务切换也不会发生!它的力度是非常强的!

2.4 挂起和恢复任务调度器适用场合

挂起调度器的方式,适用于临界区位于任务与任务之间;既不用去延时中断,又可以做到临界区的安全。就是说:它不会受到任务切换而被打断,同时又能保证中断的及时响应!

  1. 任务与任务之间的临界区:

    • 在多任务操作系统中,多个任务之间可能需要访问共享资源(例如全局变量、硬件设备等)。为了防止任务之间的资源竞争,需要保护这些访问操作。
    • 临界区是指访问共享资源的代码段,需要确保这个代码段在一个任务执行时不会被其他任务打断。
  2. 不延时中断:

    • 挂起任务调度器 (vTaskSuspendAll()) 的方式不会关闭中断,这意味着系统中的中断服务程序(ISR)仍然可以正常执行。ISR的执行不会受到挂起任务调度器的影响。
    • 由于中断没有被关闭,系统的中断响应时间不会受到影响。这样可以保证系统的实时性,因为时间关键的中断仍然能够及时处理。
  3. 临界区的安全:

    • 当任务调度器被挂起时,当前任务可以独占CPU资源执行临界区代码,而不必担心在这个过程中会被其他任务打断。这样可以确保任务间临界区的代码安全执行。
    • 任务调度器挂起期间,虽然ISR可以执行,但ISR不会引起任务切换。因此,任务执行临界区代码的过程中,不会被其他任务打断。

2.5 使用格式示例

2.6 任务挂起与恢复内部实现(了解)

至此,已经讲解完毕!初次学习,循序渐进,一步步掌握即可!以上就是全部内容!请务必掌握,创作不易,欢迎大家点赞加关注评论,您的支持是我前进最大的动力!下期再见!

这篇关于FreeRTOS基础(七):临界段代码保护及调度器挂起与恢复的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1024152

相关文章

C#实现千万数据秒级导入的代码

《C#实现千万数据秒级导入的代码》在实际开发中excel导入很常见,现代社会中很容易遇到大数据处理业务,所以本文我就给大家分享一下千万数据秒级导入怎么实现,文中有详细的代码示例供大家参考,需要的朋友可... 目录前言一、数据存储二、处理逻辑优化前代码处理逻辑优化后的代码总结前言在实际开发中excel导入很

SpringBoot+RustFS 实现文件切片极速上传的实例代码

《SpringBoot+RustFS实现文件切片极速上传的实例代码》本文介绍利用SpringBoot和RustFS构建高性能文件切片上传系统,实现大文件秒传、断点续传和分片上传等功能,具有一定的参考... 目录一、为什么选择 RustFS + SpringBoot?二、环境准备与部署2.1 安装 RustF

Python实现Excel批量样式修改器(附完整代码)

《Python实现Excel批量样式修改器(附完整代码)》这篇文章主要为大家详细介绍了如何使用Python实现一个Excel批量样式修改器,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录前言功能特性核心功能界面特性系统要求安装说明使用指南基本操作流程高级功能技术实现核心技术栈关键函

从基础到高级详解Python数值格式化输出的完全指南

《从基础到高级详解Python数值格式化输出的完全指南》在数据分析、金融计算和科学报告领域,数值格式化是提升可读性和专业性的关键技术,本文将深入解析Python中数值格式化输出的相关方法,感兴趣的小伙... 目录引言:数值格式化的核心价值一、基础格式化方法1.1 三种核心格式化方式对比1.2 基础格式化示例

Redis实现高效内存管理的示例代码

《Redis实现高效内存管理的示例代码》Redis内存管理是其核心功能之一,为了高效地利用内存,Redis采用了多种技术和策略,如优化的数据结构、内存分配策略、内存回收、数据压缩等,下面就来详细的介绍... 目录1. 内存分配策略jemalloc 的使用2. 数据压缩和编码ziplist示例代码3. 优化的

redis-sentinel基础概念及部署流程

《redis-sentinel基础概念及部署流程》RedisSentinel是Redis的高可用解决方案,通过监控主从节点、自动故障转移、通知机制及配置提供,实现集群故障恢复与服务持续可用,核心组件包... 目录一. 引言二. 核心功能三. 核心组件四. 故障转移流程五. 服务部署六. sentinel部署

Python 基于http.server模块实现简单http服务的代码举例

《Python基于http.server模块实现简单http服务的代码举例》Pythonhttp.server模块通过继承BaseHTTPRequestHandler处理HTTP请求,使用Threa... 目录测试环境代码实现相关介绍模块简介类及相关函数简介参考链接测试环境win11专业版python

Python从Word文档中提取图片并生成PPT的操作代码

《Python从Word文档中提取图片并生成PPT的操作代码》在日常办公场景中,我们经常需要从Word文档中提取图片,并将这些图片整理到PowerPoint幻灯片中,手动完成这一任务既耗时又容易出错,... 目录引言背景与需求解决方案概述代码解析代码核心逻辑说明总结引言在日常办公场景中,我们经常需要从 W

使用Spring Cache本地缓存示例代码

《使用SpringCache本地缓存示例代码》缓存是提高应用程序性能的重要手段,通过将频繁访问的数据存储在内存中,可以减少数据库访问次数,从而加速数据读取,:本文主要介绍使用SpringCac... 目录一、Spring Cache简介核心特点:二、基础配置1. 添加依赖2. 启用缓存3. 缓存配置方案方案

从基础到进阶详解Python条件判断的实用指南

《从基础到进阶详解Python条件判断的实用指南》本文将通过15个实战案例,带你大家掌握条件判断的核心技巧,并从基础语法到高级应用一网打尽,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一... 目录​引言:条件判断为何如此重要一、基础语法:三行代码构建决策系统二、多条件分支:elif的魔法三、