当前位置:网站首页>嵌入式环境下并发控制与线程安全
嵌入式环境下并发控制与线程安全
2022-07-30 11:27:00 【李肖遥】
关注、星标公众号,直达精彩内容
来源:网络素材
代码规模日益增大和基于RTOS的多线程技术使嵌入式软件开发越来越关注“并发控制和线程安全”,当多个执行线程(指正在运行代码的任意上下文,包括线程和中断服务程序)需要访问相同的共享资源时(包括软件数据和硬件资源),就可能因为竞态而导致错误。
这种错误容易制造,但很难找到,从设计上保证正确性收益更大。
竞态的产生
当一个共享资源被多个执行线程“非原子性”访问时,一个执行线程的操作被另一个执行线程打断而带来错误就叫“竞态”,共享资源包括硬件设备和软件实体。
最明显的共享是全局变量,如果定义如下数组,它被多个线程读和写,这将成为最易理解的竞态。
int g_aiGlobalBuf[100];另一种不太明显的共享是由不可重入函数造成的,如果多个线程调用了下面的函数,那么同样产生竞态。
void ProcGlobalBuf(int iPos, int iVal)
{
g_aiGlobalBuf[iPos] = iVal;
}硬件资源被多个线程使用也会引入竞态,如下面的函数(使用伪代码)被2个线程同时调用,那么第一个线程的数据可能还没有发送完毕就被第二个线程的数据“覆盖”。
void SendByDMA(const void *p_vBuf, int iSize)
{
DMA.StartAddr = p_vBuf;
DMA.Count = iSize;
EnableDMA();
}一句话:任何被多个执行线程使用的资源都可能产生“竞态”。
并发控制规则
规则一:只要可能,就应该避免资源的共享。
如果没有并发访问,就不会有竞态的产生。因此,设计代码应该具有最少的共享。这种思想的最明显应用是避免使用全局变量。如果我们将资源放在多个执行线程都会找到的地方,则必须有足够的理由。
例如硬件资源的分配中,串口只能由线程1调用,网口只能由线程2调用,LCD只能由线程3调用,那么这3种硬件资源的竞态一开始就杜绝了,同理可以应用到软件资源上。
规则二:引发竞态的共享资源必须加锁
然而,在计算机的世界里共享就是现实的生活,在单个执行线程之外共享硬件或软件资源的任何时候,因为另外一个线程可能产生对该资源的不一致观察,就必须显示地管理对该资源的访问。
像只读数据(如芯片的序列号)对于任何访问它的执行线程看来都是一致的,那么竞态是不可能发生的。
基于RTOS的嵌入式环境下对共享资源的加锁一般有3种途径:关中断、使用信号量、禁止任务切换。
关中断应用于2种情况:如果任务代码和中断程序共享资源,或者共享资源访问时间很短(如操作一个变量);如果仅线程之间访问一些共享资源且操作时间不太长,禁止任务切换可以胜任;其他情况下都将使用信号量。
规则三:被多线程调用的函数必须是可重入
一个函数是否是可重入的判断规则:
一个可重入函数一般用原子的方法使用变量,除非这些变量存储在调用这个函数的堆栈中或这些变量是任务的私有变量。
一个可重入函数一般不调用其他的不可重入的函数。
一个可重入函数一般不用非原子的方法使用硬件。
锁的使用规则
当我们创建一个可被并行访问的对象时,应该同时定义用来控制访问的锁。锁定模式必须在一开始就安排好,否则其后的改进将会非常困难。
如果某个获得锁的函数要调用其他同样试图获取这个锁的函数,我们的代码就会死锁,即不允许锁拥有者第二次获得这个锁;如果试图这么做,系统将持起。
提供给外部调用的函数必须显示地处理锁定,在编写那些假定调用者已处理了锁定的内部函数时,我们自己应该显示地说明这种假定,否则几个月后再回头来看这些代码时,很难记清在调用某个特定函数时是否需要拥有锁。
尽可能避免出现需要多个锁的情况,实在需要多个锁就要防止死锁的发生:始终以相同的顺序获得锁,并且了解其他代码操作锁的做法;先获取自己局部锁,再获取其他锁;在拥有锁时尽量避免线程被挂起,那样会导致实时性下降,甚至永久性挂起系统。
原文链接:https://blog.csdn.net/jiangjunjie_2005/article/details/30713585
版权声明:本文来源网络,免费传达知识,版权归原作者所有。如涉及作品版权问题,请联系我进行删除。
‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧ END ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧
关注我的微信公众号,回复“加群”按规则加入技术交流群。点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。边栏推荐
- High energy output!Tencent's internal MyCat middleware manual, both theoretical and practical
- decodeURIComponent()、eval()、encodeURIComponent()
- Beyond Stream Processing!The 4th real-time computing Flink challenge is launched, and 490,000 prizes are waiting for you!
- 基于MySQL数据库,Redis缓存,MQ消息中间件,ES搜索引擎的高可用方案解析
- Verilog grammar basics HDL Bits training 08
- 2022-07-29 顾宇佳 学习笔记 异常处理
- spin lock和mutex使用场景的差异
- 明德扬FPGA开发板XILINX-K7核心板Kintex7 XC7K325 410T工业级
- 向上管理读书笔记
- Native js create table
猜你喜欢
随机推荐
xshell使用技巧(赚分享平台怎么样)
Current relay JL-8GB/11/AC220V
Hu-cang integrated e-commerce project (1): project background and structure introduction
湖仓一体电商项目(一):项目背景和架构介绍
PanGu-Coder: Function-level code generation model
高能产出!腾讯内部的MyCat中间件手册,理论实操齐下
单片机开发之LCD1602显示实验
Performance testing of API Gateway APISIX on Google Cloud T2A and T2D
文本的对齐方式、行高、空间 等总结
定制.NET 6.0的依赖注入
单片机开发之静态LED显示
TensorFlow custom training function
GBJ2510-ASEMI电机专用25A整流桥GBJ2510
面试官:Redis中的布隆过滤器与布谷鸟过滤器,你了解多少?
分布式限流 redission RRateLimiter 的使用及原理
NLP领域的最新研究进展
decodeURIComponent()、eval()、encodeURIComponent()
久经沙场的程序员居然也被某鱼的假程序员骗了,程序员之间的信任应该是最高的,他一个人毁了这种信任感
不用if分支对同一个变量做判断的方法
[ASP.NET Core] Dependency Injection for Option Classes









