我在马路上遇到一个死锁问题

嵌入式ARM 2020-07-03

▍马路上的死锁问题


我在市里的老区马路上遇到堵车了,动弹不得,后来发现是个“死锁”问题。

当时我坐在③号车里,等了好久,忽然职业病犯了,好想下车跟他们讲解下发生了什么,“死锁”是怎么造成的,如何避免……


简要情况,见下图,原因是右上方的小路一次只能通过一个方向的车,大路上红色的车可能因为没找到车位,随便停路边了,导致图中①、②、③、④、⑤号车动弹不得。

实际上,在拥堵的马路,如果没有交通指示的话,很容易造成类似这种“死锁”。如下图这种情形。

除了交通上这个案例,我们再来看看网络上的一张趣图(姑且叫人质问题,图来源于https://stackoverflow.com/questions/34512/what-is-a-deadlock叫Criminal & Cop Scene):

扯远了,我们还是认真地聊聊这个“死锁”问题吧。

▍锁的概念

锁是什么?其实概念很简单,就是平时我们见到的锁。只是操作系统仿照现实上的这个概念做了一套逻辑而已。原理,我还是可以从现实生活中去理解的。

例如,你去买衣服,店里有试衣间。当你想试一下衣服的时候,就可能要用到试衣间,你进了试衣间,就要将门锁上,表示你当时占用试衣间这个资源,用完就释放,然后别人就可以用了。试想下,如果你不锁门,代价可能就是春光乍泄了……

如果你买衣服从没进过试衣间,那就自己脑补下上公共厕所的例子吧……


回到软件上的锁概念,一般OS会提供两种接口来访问这个锁,一个是Acquire或者叫Require/Get/Wait,一个Release,即表示占有并锁上资源和释放这个资源。

一般RTOS会用Semaphore或者Mutex来实现这个锁的功能,当然,复杂的系统如Linux会有更多种类的锁,如自旋锁,互斥锁,读写锁等等。

▍锁的作用

这还用说吗,目的只有一个,你占用的时候,不想被被人占有。防止各种各样的问题。例如,上厕所记得把门锁上,不然别人推开了,你会骂人家流氓,或者,人家也骂你流氓,上厕所不锁门……

还有哦,算了,程序员有女朋友吗?有的话,差不多就要去扯证,长期官方锁上……哈哈哈

▍死锁的原因


情景1:嵌套锁/递归锁的使用

上段代码来看看:

task1在第一个Doing someting中被task2抢占,死锁就开始了。这是一种嵌套锁使用遇到的死锁情形。递归锁(如果你真用过,那真有装逼的嫌疑了),也会有这样的问题。

现实项目中,可能会更隐秘,找到它需要花点心思。


情景2:锁还没被释放,Task却被kill了

RTOS设计的没那么智能,task被kill,其所占有的资源不一定会被自动释放。这种情形,很容易发生在关机的流程。设计上一定要非常谨慎。


情景3:Task给自己发mailbox

Tasks之间的通信,我们一般都是用mailbox,同一个task的mailbox接口可以被多个其他task调用,也不会发生资源冲突问题。实际上,mailbox内也隐藏着一个锁的功能,一个task调用了mailbox接口,其他task只能等它调用完了,才能调用。

一般定义的mailbox是一个空间有限的队列,在频繁调用的时候,资源不够,不让正在调用的task在等。这实际上很正常,不正常的时候,如果task自己调用了自己的mailbox接口,那就容易见鬼了。

假如上图的task1优先级很低,定义的mailbox大小为4,都被task2、task3、task4、task5被调用了,而task1还没来得及处理释放mailbox资源。正在此时task1的某些应用代码也需要发一个消息,调用了自己的mailbox接口,然后就死了……

▍死锁的避免

使用锁的注意事项,不详细解释了,总结以下几条:

  1. 不允许使用嵌套锁,即不要用锁中锁;

  2. 不允许使用递归锁,这个跟嵌套锁类似;

  3. 不要在中断服务中使用锁;

  4. Task或者Thread被kill之前,确保其占有的锁已经释放了;

  5. Require资源的时候,尽量不用死等(即超时为Forever)。


-END-


本文授权转载自公众号“嵌入式软件实战派”,作者:实战派大师兄





推荐阅读



【01】一文教你搞懂C语言的Q格式使用
【02】万字长文给“DNS”带绿帽
【03】6年字节跳动程序员获0.5-4亿期权?年仅28岁的郭宇宣布退休……
【04】MATLAB 只是冰山一角!海外资深程序员聊聊“卡脖子”……
【05】21岁到华为,单板焊板一焊就是28年!




免责声明:整理文章为传播相关技术,版权归原作者所有,如有侵权,请联系删除
技术,源于生活!   ↓↓↓


嵌入式ARM 关注这个时代最火的嵌入式ARM,你想知道的都在这里。
评论
热门推荐
相关推荐
我要评论
0
0
点击右上角,分享到朋友圈 我知道啦
请使用浏览器分享功能 我知道啦