热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

通过临界区实现RTOS中任务之间共享资源的保护

通过临界区实现RTOS任务之间共享资源的保护概述上节在共享资源的介绍中我们介绍了共享资源面临的准确性、完整性容易遭到破坏的一些场景。临界区是为了避免并行访问共享资源导致非期望




通过临界区实现 RTOS 任务之间共享资源的保护

概述

上节在共享资源的介绍中我们介绍了共享资源面临的准确性、完整性容易遭到破坏的一些场景。

临界区是为了避免并行访问共享资源导致非期望或者错误行为而保护对应资源的一种机制。

具体来讲,临界区是一种上锁-去锁机制,建立临界区后,就对该段代码进行了上锁,其他任务、中断均无法再次进入该段代码,除非去锁。
在这里插入图片描述

典型的用法是:

taskENTER_CRITICAL();// 加锁
code();//关键代码
taskEXIT_CRITICAL();// 去锁

注意,临界区其实只是一个通俗的使用上锁-去锁机制保护一段代码的概念,实现临界区的方法有很多,临界区本身的性质在不同 RTOS 系统中也不同,比如有的系统中临界区是支持嵌套的,有的则不支持嵌套。在大部分 RTOS 系统,通过**关闭全局中断来实现临界区机制。**即上述 API 对应的底层逻辑是:

// 关闭全局中断
// 关键代码
// 重新启动全局中断

ESP-IDF 中对临界区的实现是关闭不大于 configMAX_SYSCALL_INTERRUPT_PRIORITY中断的所有中断(包括 SysTick 中断)。同时,一些 ESP32是双核 CPU 系统,因此不同于传统的 RTOS 系统,ESP-IDF 中的临界区中增加了一个变量来实现这种机制:

taskENTER_CRITICAL(&mux);// 加锁
code();//关键代码
taskEXIT_CRITICAL(&mux);// 去锁

其对应的底层逻辑是:

// 关闭全局中断,去获得 mux 锁
// 关键代码
// 重新启动全局中断,释放 mux 锁

需求及功能解析


临界区为什么能实现共享资源的保护

在 RTOS 中的任务调度与三种任务模型 章节中,我们介绍了任务的调度是通过 SysTick 中断完成的,即每个 SysTick 中断到来时都会触发任务调度器工作,检查是否需要切换任务,即更换 CPU 的使用权。

如前所述,临界区是通过关闭全局中断来实现的,这其中包括 SysTick 中断。即调用进入临界区的 API后,设备的中断停止了,这导致了两个方面的变化:

1)SysTick 中断被禁用,无法触发任务切换,因此临界区内的代码,不会被其他任务打断执行。

2)设备中断被禁用,无法响应新的中断,因此临界区内的代码,不会被其他中断打断执行。

所以,临界区内的代码在每次使用时都是独占的,完全不会被干扰。


临界区的副作用

1)对任务而言,SysTick 中断被禁用,无法触发任务切换,因此同优先级任务、高优先级任务均无法被执行,对任务的实时调度产生影响。

2)对中断而言,设备中断被禁用,无法响应新的中断,因此设备的中断响应实时性遭到破坏。

总结:得于斯者毁于斯,因此临界区在发挥作用时,也有对应得副作用。


临界区内代码的设计原则

1)临界区应尽可能短。如果可能,将尽可能多的处理和/或事件处理推迟到临界区之外。
2)临界段持续的时间越长,挂起的中断延迟的时间就越长,因此对于读操作,最好只是拷贝原时值,对于写操作,最好只是更改原始值的简单操作。
3)典型的临界区应该只访问几个数据结构和/或硬件寄存器。
4)FreeRTOS API不应在临界区内调用。
5)用户不应在临界区内调用任何阻塞(block)或会停止代码执行直到它完成才返回的函数(这类函数学名叫 yielding functions)。


示例解析

上节在共享资源的介绍中我们介绍了共享资源面临的准确性、完整性容易遭到破坏的一些场景。一种简单的示例是一个任务对全局变量执行 10 次 加1 操作,一个任务对全局变量执行 10 次 减1 操作,最终该全局变量的值一定是 0?答案是否定的。因此本节演示使用临界区这种机制后的情况,这种错误会被避免掉。

不添加临界区的情况下,执行的结果如下:

This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, Minimum free heap size: 295348 bytes
task1 done
task2 done
task3 done, and counter=-11

添加临界区得的情况下,执行的最终结果才正确为0,具体 log 显示如下:

This is esp32 chip with 2 CPU core(s), WiFi/BT/BLE, Minimum free heap size: 295340 bytes
task1 done
task2 done
task3 done, and counter=0

小伙伴们可以在测试程序中进行验证这两种情况。


讨论

1)ESP-IDF 中的临界区对嵌套使用的支持

支持嵌套,去锁的个数应与上锁的个数相同:

taskENTER_CRITICAL(&mux);
code1();//关键代码1

taskENTER_CRITICAL(&mux);
code2();//关键代码2
taskEXIT_CRITICAL(&mux);

taskEXIT_CRITICAL(&mux);

总结

1)临界区是为了避免并行访问共享资源导致非期望或者错误行为而保护对应资源的一种上锁-去锁机制。

2)实现临界区的方法有很多,在大部分 RTOS 系统,通过关闭全局中断来实现临界区机制,ESP32 中也是如此。

3)ESP32 是双核系统,因此对临界区的 API 添加了一个参数 mutex 来保证双核下的临界区工作正常。

4)临界区可以保证临界区内的代码不被中断、任务打断。

5)临界区有副作用,因此临界区内的代码应该尽可能短,并且不能包含任何延时或在阻塞。我们将在下节讲述影响更小的共享资源保护方法。


资源链接

1)Learning-FreeRTOS-with-esp32 系列博客介绍
2)对应示例的 code 链接 (点击直达代码仓库)

3)下一篇:







推荐阅读
  • 不同优化算法的比较分析及实验验证
    本文介绍了神经网络优化中常用的优化方法,包括学习率调整和梯度估计修正,并通过实验验证了不同优化算法的效果。实验结果表明,Adam算法在综合考虑学习率调整和梯度估计修正方面表现较好。该研究对于优化神经网络的训练过程具有指导意义。 ... [详细]
  • CF:3D City Model(小思维)问题解析和代码实现
    本文通过解析CF:3D City Model问题,介绍了问题的背景和要求,并给出了相应的代码实现。该问题涉及到在一个矩形的网格上建造城市的情景,每个网格单元可以作为建筑的基础,建筑由多个立方体叠加而成。文章详细讲解了问题的解决思路,并给出了相应的代码实现供读者参考。 ... [详细]
  • 本文讨论了在openwrt-17.01版本中,mt7628设备上初始化启动时eth0的mac地址总是随机生成的问题。每次随机生成的eth0的mac地址都会写到/sys/class/net/eth0/address目录下,而openwrt-17.01原版的SDK会根据随机生成的eth0的mac地址再生成eth0.1、eth0.2等,生成后的mac地址会保存在/etc/config/network下。 ... [详细]
  • 本文介绍了如何使用PHP向系统日历中添加事件的方法,通过使用PHP技术可以实现自动添加事件的功能,从而实现全局通知系统和迅速记录工具的自动化。同时还提到了系统exchange自带的日历具有同步感的特点,以及使用web技术实现自动添加事件的优势。 ... [详细]
  • GetWindowLong函数
    今天在看一个代码里头写了GetWindowLong(hwnd,0),我当时就有点费解,靠,上网搜索函数原型说明,死活找不到第 ... [详细]
  • VScode格式化文档换行或不换行的设置方法
    本文介绍了在VScode中设置格式化文档换行或不换行的方法,包括使用插件和修改settings.json文件的内容。详细步骤为:找到settings.json文件,将其中的代码替换为指定的代码。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文介绍了[从头学数学]中第101节关于比例的相关问题的研究和修炼过程。主要内容包括[机器小伟]和[工程师阿伟]一起研究比例的相关问题,并给出了一个求比例的函数scale的实现。 ... [详细]
  • 本文介绍了Oracle数据库中tnsnames.ora文件的作用和配置方法。tnsnames.ora文件在数据库启动过程中会被读取,用于解析LOCAL_LISTENER,并且与侦听无关。文章还提供了配置LOCAL_LISTENER和1522端口的示例,并展示了listener.ora文件的内容。 ... [详细]
  • 利用Visual Basic开发SAP接口程序初探的方法与原理
    本文介绍了利用Visual Basic开发SAP接口程序的方法与原理,以及SAP R/3系统的特点和二次开发平台ABAP的使用。通过程序接口自动读取SAP R/3的数据表或视图,在外部进行处理和利用水晶报表等工具生成符合中国人习惯的报表样式。具体介绍了RFC调用的原理和模型,并强调本文主要不讨论SAP R/3函数的开发,而是针对使用SAP的公司的非ABAP开发人员提供了初步的接口程序开发指导。 ... [详细]
  • C++字符字符串处理及字符集编码方案
    本文介绍了C++中字符字符串处理的问题,并详细解释了字符集编码方案,包括UNICODE、Windows apps采用的UTF-16编码、ASCII、SBCS和DBCS编码方案。同时说明了ANSI C标准和Windows中的字符/字符串数据类型实现。文章还提到了在编译时需要定义UNICODE宏以支持unicode编码,否则将使用windows code page编译。最后,给出了相关的头文件和数据类型定义。 ... [详细]
  • Go Cobra命令行工具入门教程
    本文介绍了Go语言实现的命令行工具Cobra的基本概念、安装方法和入门实践。Cobra被广泛应用于各种项目中,如Kubernetes、Hugo和Github CLI等。通过使用Cobra,我们可以快速创建命令行工具,适用于写测试脚本和各种服务的Admin CLI。文章还通过一个简单的demo演示了Cobra的使用方法。 ... [详细]
  • WebSocket与Socket.io的理解
    WebSocketprotocol是HTML5一种新的协议。它的最大特点就是,服务器可以主动向客户端推送信息,客户端也可以主动向服务器发送信息,是真正的双向平等对话,属于服务器推送 ... [详细]
  • 怎么在PHP项目中实现一个HTTP断点续传功能发布时间:2021-01-1916:26:06来源:亿速云阅读:96作者:Le ... [详细]
  • 深入理解Kafka服务端请求队列中请求的处理
    本文深入分析了Kafka服务端请求队列中请求的处理过程,详细介绍了请求的封装和放入请求队列的过程,以及处理请求的线程池的创建和容量设置。通过场景分析、图示说明和源码分析,帮助读者更好地理解Kafka服务端的工作原理。 ... [详细]
author-avatar
我的小姑奶奶呦_960
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有