我在馬路上遇到一個(gè)死鎖問題
掃描二維碼
隨時(shí)隨地手機(jī)看文章
▍馬路上的死鎖問題
我在市里的老區(qū)馬路上遇到堵車了,動彈不得,后來發(fā)現(xiàn)是個(gè)“死鎖”問題。
當(dāng)時(shí)我坐在③號車?yán)?,等了好久,忽然職業(yè)病犯了,好想下車跟他們講解下發(fā)生了什么,“死鎖”是怎么造成的,如何避免……
簡要情況,見下圖,原因是右上方的小路一次只能通過一個(gè)方向的車,大路上紅色的車可能因?yàn)闆]找到車位,隨便停路邊了,導(dǎo)致圖中①、②、③、④、⑤號車動彈不得。
實(shí)際上,在擁堵的馬路,如果沒有交通指示的話,很容易造成類似這種“死鎖”。如下圖這種情形。
除了交通上這個(gè)案例,我們再來看看網(wǎng)絡(luò)上的一張趣圖(姑且叫人質(zhì)問題,圖來源于https://stackoverflow.com/questions/34512/what-is-a-deadlock叫Criminal & Cop Scene):
扯遠(yuǎn)了,我們還是認(rèn)真地聊聊這個(gè)“死鎖”問題吧。
▍鎖的概念
鎖是什么?其實(shí)概念很簡單,就是平時(shí)我們見到的鎖。只是操作系統(tǒng)仿照現(xiàn)實(shí)上的這個(gè)概念做了一套邏輯而已。原理,我還是可以從現(xiàn)實(shí)生活中去理解的。
例如,你去買衣服,店里有試衣間。當(dāng)你想試一下衣服的時(shí)候,就可能要用到試衣間,你進(jìn)了試衣間,就要將門鎖上,表示你當(dāng)時(shí)占用試衣間這個(gè)資源,用完就釋放,然后別人就可以用了。試想下,如果你不鎖門,代價(jià)可能就是春光乍泄了……
如果你買衣服從沒進(jìn)過試衣間,那就自己腦補(bǔ)下上公共廁所的例子吧……
回到軟件上的鎖概念,一般OS會提供兩種接口來訪問這個(gè)鎖,一個(gè)是Acquire或者叫Require/Get/Wait,一個(gè)Release,即表示占有并鎖上資源和釋放這個(gè)資源。
一般RTOS會用Semaphore或者M(jìn)utex來實(shí)現(xiàn)這個(gè)鎖的功能,當(dāng)然,復(fù)雜的系統(tǒng)如Linux會有更多種類的鎖,如自旋鎖,互斥鎖,讀寫鎖等等。
▍鎖的作用
這還用說嗎,目的只有一個(gè),你占用的時(shí)候,不想被被人占有。防止各種各樣的問題。例如,上廁所記得把門鎖上,不然別人推開了,你會罵人家流氓,或者,人家也罵你流氓,上廁所不鎖門……
還有哦,算了,程序員有女朋友嗎?有的話,差不多就要去扯證,長期官方鎖上……哈哈哈
▍死鎖的原因
情景1:嵌套鎖/遞歸鎖的使用
上段代碼來看看:
task1在第一個(gè)Doing someting中被task2搶占,死鎖就開始了。這是一種嵌套鎖使用遇到的死鎖情形。遞歸鎖(如果你真用過,那真有裝逼的嫌疑了),也會有這樣的問題。
現(xiàn)實(shí)項(xiàng)目中,可能會更隱秘,找到它需要花點(diǎn)心思。
情景2:鎖還沒被釋放,Task卻被kill了
RTOS設(shè)計(jì)的沒那么智能,task被kill,其所占有的資源不一定會被自動釋放。這種情形,很容易發(fā)生在關(guān)機(jī)的流程。設(shè)計(jì)上一定要非常謹(jǐn)慎。
情景3:Task給自己發(fā)mailbox
Tasks之間的通信,我們一般都是用mailbox,同一個(gè)task的mailbox接口可以被多個(gè)其他task調(diào)用,也不會發(fā)生資源沖突問題。實(shí)際上,mailbox內(nèi)也隱藏著一個(gè)鎖的功能,一個(gè)task調(diào)用了mailbox接口,其他task只能等它調(diào)用完了,才能調(diào)用。
一般定義的mailbox是一個(gè)空間有限的隊(duì)列,在頻繁調(diào)用的時(shí)候,資源不夠,不讓正在調(diào)用的task在等。這實(shí)際上很正常,不正常的時(shí)候,如果task自己調(diào)用了自己的mailbox接口,那就容易見鬼了。
假如上圖的task1優(yōu)先級很低,定義的mailbox大小為4,都被task2、task3、task4、task5被調(diào)用了,而task1還沒來得及處理釋放mailbox資源。正在此時(shí)task1的某些應(yīng)用代碼也需要發(fā)一個(gè)消息,調(diào)用了自己的mailbox接口,然后就死了……
▍死鎖的避免
使用鎖的注意事項(xiàng),不詳細(xì)解釋了,總結(jié)以下幾條:
不允許使用嵌套鎖,即不要用鎖中鎖;
不允許使用遞歸鎖,這個(gè)跟嵌套鎖類似;
不要在中斷服務(wù)中使用鎖;
Task或者Thread被kill之前,確保其占有的鎖已經(jīng)釋放了;
Require資源的時(shí)候,盡量不用死等(即超時(shí)為Forever)。
-END-
本文授權(quán)轉(zhuǎn)載自公眾號“嵌入式軟件實(shí)戰(zhàn)派”,作者:實(shí)戰(zhàn)派大師兄
推薦閱讀
免責(zé)聲明:本文內(nèi)容由21ic獲得授權(quán)后發(fā)布,版權(quán)歸原作者所有,本平臺僅提供信息存儲服務(wù)。文章僅代表作者個(gè)人觀點(diǎn),不代表本平臺立場,如有問題,請聯(lián)系我們,謝謝!






