当前位置:网站首页>嵌入式环境下并发控制与线程安全
嵌入式环境下并发控制与线程安全
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 ‧‧‧‧‧‧‧‧‧‧‧‧‧‧‧
关注我的微信公众号,回复“加群”按规则加入技术交流群。点击“阅读原文”查看更多分享,欢迎点分享、收藏、点赞、在看。边栏推荐
- 原生js 创建表格
- 单片机开发之ADC0808/9信号采集
- Underwater target detection method based on spatial feature selection
- 不用if分支对同一个变量做判断的方法
- 明德扬FPGA开发板XILINX-K7核心板Kintex7 XC7K325 410T工业级
- LeetCode_236_Last Common Ancestor of a Binary Tree
- 《跟唐老师学习云网络》 - 问题定位 - 主机通但容器不通
- 美团内推+校招笔试题+知识点总结
- contentDocument contentWindow, canvas, svg, iframe
- 周鸿祎:微软抄袭了360安全模式 所以成为美国最大的安全公司
猜你喜欢
随机推荐
单片机开发之LCD1602显示实验
EA中的业务对象和业务实体你分得清吗?
decodeURIComponent()、eval()、encodeURIComponent()
The use and principle of distributed current limiting reduction RRateLimiter
[Cloud-Building Co-creation] Huawei Cloud and Hongmeng collaborate to cultivate innovative developers
云原生应用的概念和云原生应用的 15 个特征
ABP学习资源整理
Jingdong school recruited written test questions + summary of knowledge points
contentDocument contentWindow, canvas, svg, iframe
Swift common extension classes and simple encapsulation
Voltage relay HDY - vac - 1 A / 1-220
数字量输入输出模块DAM-5088
流水线上的农民:我在工厂种蔬菜
Current relay JL-8GB/11/AC220V
LeetCode_236_二叉树的最近公共祖先
柔性机械系统分布参数建模及其控制的研究与进展
VSCode更改插件的安装位置
文本的对齐方式、行高、空间 等总结
The battle-hardened programmer was also deceived by a fake programmer from a certain fish. The trust between programmers should be the highest, and he alone destroyed this sense of trust
PL5920 SOT-23-6 21V、2A、600KHz同步降压DC/DC转换器










