当前位置:网站首页>嵌入式环境下并发控制与线程安全
嵌入式环境下并发控制与线程安全
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 ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧
关注我的微信公众号,回复“加群”按规则加入技术交流群。点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。边栏推荐
- Based on sliding mode control of uncertain neutral system finite time stable
- LeetCode_235_二叉搜索树的最近公共祖先
- 数字量输入输出模块DAM-5088
- 电流继电器JL-8GB/11/AC220V
- Interviewer: Redis bloom filter and the cuckoo in the filter, how much do you know?
- 又爆神作!阿里爆款MySQL高级宝典开源,直抵P7
- Explain the problem of change exchange in simple terms - the shell of the backpack problem
- Beyond Stream Processing!The 4th real-time computing Flink challenge is launched, and 490,000 prizes are waiting for you!
- Typroa alternative tool marktext
- 单片机开发之LCD1602显示实验
猜你喜欢
随机推荐
编译Hudi
High energy output!Tencent's internal MyCat middleware manual, both theoretical and practical
I built another wheel: GrpcGateway
[ASP.NET Core] Dependency Injection for Option Classes
MySQL database maintenance
自定义查询--关于倒排索引的研究
[Cloud-Building Co-creation] Huawei Cloud and Hongmeng collaborate to cultivate innovative developers
C# 枚举类型 于xaml 中区别
久经沙场的程序员居然也被某鱼的假程序员骗了,程序员之间的信任应该是最高的,他一个人毁了这种信任感
云原生应用的概念和云原生应用的 15 个特征
AIX shell获取前几个月时间
UE5 GAS Study Notes Postscript 0
牛客-TOP101-BM42
ORA-00600 [13013], [5001], [268] 问题分析及恢复
HJY-F931A/YJ三相电压继电器
STM32F1读取MLX90632非接触式红外温度传感器
基于声信道分析的电缆隧道人员定位技术
AB test summary
MySQL——数据库基础
2022-07-29 顾宇佳 学习笔记 异常处理










