在并發(fā)程序設(shè)計(jì)中,死鎖 (deadlock) 是一種十分常見的邏輯錯(cuò)誤。通過采用正確的編程方式,死鎖的發(fā)生不難避免。
死鎖的四個(gè)必要條件
在計(jì)算機(jī)專業(yè)的本科教材中,通常都會(huì)介紹死鎖的四個(gè)必要條件。這四個(gè)條件缺一不可,或者說只要破壞了其中任何一個(gè)條件,死鎖就不可能發(fā)生。我們來復(fù)習(xí)一下,這四個(gè)條件是:
?互斥(Mutual exclusion):存在這樣一種資源,它在某個(gè)時(shí)刻只能被分配給一個(gè)執(zhí)行緒(也稱為線程)使用;
?持有(Hold and wait):當(dāng)請(qǐng)求的資源已被占用從而導(dǎo)致執(zhí)行緒阻塞時(shí),資源占用者不但無需釋放該資源,而且還可以繼續(xù)請(qǐng)求更多資源;
?不可剝奪(No preemption):執(zhí)行緒獲得到的互斥資源不可被強(qiáng)行剝奪,換句話說,只有資源占用者自己才能釋放資源;
?環(huán)形等待(Circular wait):若干執(zhí)行緒以不同的次序獲取互斥資源,從而形成環(huán)形等待的局面,想象在由多個(gè)執(zhí)行緒組成的環(huán)形鏈中,每個(gè)執(zhí)行緒都在等待下一個(gè)執(zhí)行緒釋放它持有的資源。
解除死鎖的必要條件
不難看出,在死鎖的四個(gè)必要條件中,第二、三和四項(xiàng)條件比較容易消除。通過引入事務(wù)機(jī)制,往往可以消除第二、三兩項(xiàng)條件,方法是將所有上鎖操作均作為事務(wù)對(duì)待,一旦開始上鎖,即確保全部操作均可回退,同時(shí)通過鎖管理器檢測死鎖,并剝奪資源(回退事務(wù))。這種做法有時(shí)會(huì)造成較大開銷,而且也需要對(duì)上鎖模式進(jìn)行較多改動(dòng)。
消除第四項(xiàng)條件是比較容易且代價(jià)較低的辦法。具體來說這種方法約定:上鎖的順序必須一致。具體來說,我們?nèi)藶榈亟o鎖指定一種類似“水位”的方向性屬性。無論已持有任何鎖,該執(zhí)行緒所有的上鎖操作,必須按照一致的先后順序從低到高(或從高到低)進(jìn)行,且在一個(gè)系統(tǒng)中,只允許使用一種先后次序。
請(qǐng)注意,放鎖的順序并不會(huì)導(dǎo)致死鎖。也就是說,盡管按照 鎖A, 鎖B, 放A, 放B 這樣的順序來進(jìn)行鎖操作看上去有些怪異,但是只要大家都按先A后B的順序上鎖,便不會(huì)導(dǎo)致死鎖。
舉例
假如有三個(gè)對(duì)象A、B、C,我們?nèi)藶榧s定它們的鎖序是: A 先于 B 先于 C。舉例說來,下列鎖序均為合法:
? 鎖C,放C
? 鎖B,放B
? 鎖B,鎖C,放B,放C
? 鎖B,鎖C,放C,放B
? 鎖A,放A
? 鎖A,鎖C,放A,放C
? 鎖A,鎖C,放C,放A
? 鎖A,鎖B,放A,放B
? 鎖A,鎖B,放B,放A
? 鎖A,鎖B,鎖C,放A,放B,放C
? 鎖A,鎖B,鎖C,放C,放B,放A
而在上面定義的系統(tǒng)中,可能導(dǎo)致發(fā)生死鎖典型上鎖序列包括:
? 鎖B,鎖A,鎖C,放C,放A,放B
(因?yàn)橄菳后A的上鎖順序違反了鎖序約定,如果另一執(zhí)行緒同時(shí)按照先A后B的順序上鎖,則可能由于執(zhí)行緒甲獲得了B,執(zhí)行緒乙獲得了A,而導(dǎo)致雙方同時(shí)等待對(duì)方釋放所持有的鎖,從而形成死鎖局面;解法是將操作序列中增加適當(dāng)?shù)逆i操作,即改為鎖B,放B,鎖A,鎖B,鎖C,放C,放A,放B)
或者說,只要拿鎖的時(shí)候不出現(xiàn)逆序(例如拿著C的時(shí)候試圖抓B或A,或者拿著B的時(shí)候試圖抓A),并出現(xiàn)潛在逆序的時(shí)候先放掉“小”鎖再抓大的,就一定不造成死鎖了。
1、避免給一個(gè)鎖嵌套上鎖,在持有一個(gè)鎖的時(shí)候,不要再給這個(gè)鎖上鎖。
如果使用多個(gè)鎖,使用std::lock。2、在持有鎖時(shí),不要調(diào)用別人提供的函數(shù),因?yàn)槟悴磺宄e人的代碼怎么實(shí)現(xiàn)的,不知道它是不是在使用鎖。
3、給多個(gè)鎖上鎖時(shí),固定順序。如果在給多個(gè)所上鎖,并且無法使用std::lock,最好的做法就是在每一個(gè)線程中,都按照同樣的順序。
4、分層次來使用鎖,把程序分成幾個(gè)層次。區(qū)分每個(gè)層次中使用的鎖,當(dāng)一個(gè)線程已經(jīng)持有更低層次的鎖時(shí),不允許使用高層次的鎖。
可以在程序運(yùn)行時(shí)給不同的鎖加上層次號(hào),記錄每個(gè)線程持有的鎖。擴(kuò)展資料:解決方法在系統(tǒng)中已經(jīng)出現(xiàn)死鎖后,應(yīng)該及時(shí)檢測到死鎖的發(fā)生,并采取適當(dāng)?shù)拇胧﹣斫獬梨i。
死鎖預(yù)防。這是一種較簡單和直觀的事先預(yù)防的方法。
方法是通過設(shè)置某些限制條件,去破壞產(chǎn)生死鎖的四個(gè)必要條件中的一個(gè)或者幾個(gè),來預(yù)防發(fā)生死鎖。預(yù)防死鎖是一種較易實(shí)現(xiàn)的方法,已被廣泛使用。
但是由于所施加的限制條件往往太嚴(yán)格,可能會(huì)導(dǎo)致系統(tǒng)資源利用率和系統(tǒng)吞吐量降低。死鎖避免。
系統(tǒng)對(duì)進(jìn)程發(fā)出的每一個(gè)系統(tǒng)能夠滿足的資源申請(qǐng)進(jìn)行動(dòng)態(tài)檢查,并根據(jù)檢查結(jié)果決定是否分配資源;如果分配后系統(tǒng)可能發(fā)生死鎖,則不予分配,否則予以分配。這是一種保證系統(tǒng)不進(jìn)入死鎖狀態(tài)的動(dòng)態(tài)策略。
死鎖檢測和解除。先檢測:這種方法并不須事先采取任何限制性措施,也不必檢查系統(tǒng)是否已經(jīng)進(jìn)入不安全區(qū),此方法允許系統(tǒng)在運(yùn)行過程中發(fā)生死鎖。
但可通過系統(tǒng)所設(shè)置的檢測機(jī)構(gòu),及時(shí)地檢測出死鎖的發(fā)生,并精確地確定與死鎖有關(guān)的進(jìn)程和資源。檢測方法包括定時(shí)檢測、效率低時(shí)檢測、進(jìn)程等待時(shí)檢測等。
然后解除死鎖:采取適當(dāng)措施,從系統(tǒng)中將已發(fā)生的死鎖清除掉。這是與檢測死鎖相配套的一種措施。
當(dāng)檢測到系統(tǒng)中已發(fā)生死鎖時(shí),須將進(jìn)程從死鎖狀態(tài)中解脫出來。常用的實(shí)施方法是撤銷或掛起一些進(jìn)程,以便回收一些資源,再將這些資源分配給已處于阻塞狀態(tài)的進(jìn)程,使之轉(zhuǎn)為就緒狀態(tài),以繼續(xù)運(yùn)行。
死鎖的檢測和解除措施,有可能使系統(tǒng)獲得較好的資源利用率和吞吐量,但在實(shí)現(xiàn)上難度也最大。參考資料:死鎖百度百科。
破壞互斥條件
破壞互斥條件即允許多個(gè)進(jìn)程同時(shí)訪問資源。由于多數(shù)資源的必須互斥訪問這一固有特性不能改變,因此,死鎖的預(yù)防通過破壞這個(gè)必要條件實(shí)現(xiàn)在很多場合是行不通的。例如,打印機(jī)資源必須互斥使用,否則幾個(gè)進(jìn)程同時(shí)使用,每個(gè)進(jìn)程各打印一行,這種輸出信息的方式顯然是不能被用戶接受的。
破壞占有和等待條件
采用資源靜態(tài)分配法可破壞這一條件,該方法是指在進(jìn)程運(yùn)行前,一次性地_請(qǐng)分配它運(yùn)行所需的全部資源。若系統(tǒng)有足夠的資源分配給某一進(jìn)程,則一次性地將其所需資源分配給該進(jìn)程,這樣,在進(jìn)程運(yùn)行期間便不會(huì)再提出任何資源請(qǐng)求,從而使等待條件不成立。如果分配時(shí)有一種資源要求不能滿足,則進(jìn)程需要的其他資源也先不分配給進(jìn)程,從而避免進(jìn)程在等待期間占用任何資源,破壞了占用條件,從而避免死鎖的發(fā)生。
該方法控制簡單且容易實(shí)現(xiàn),但由于進(jìn)程運(yùn)行期間對(duì)所需資源的全部占用,使得某些使用時(shí)間很短的資源被長時(shí)間占用,這樣會(huì)嚴(yán)重影響系統(tǒng)資源的充分利用,導(dǎo)致資源利用率降低,同吋也影響到未獲得全部資源的進(jìn)程推遲運(yùn)行。
破壞不剝奪條件
采用剝奪式控制方法可以破壞該條件,該方法是使一個(gè)已保持了某些資源的進(jìn)程,由于新的資源要求目前得不到滿足,它必須先暫時(shí)釋放巳保持的所有資源(一種剝奪式),然后去等待,以后再一起向系統(tǒng)提出巾請(qǐng),這樣也能防止死鎖。這種方法實(shí)現(xiàn)起來相對(duì)W難,為了保護(hù)進(jìn)程自動(dòng)放棄資源的現(xiàn)場以及后來的再次恢復(fù),需要付出高昂的代價(jià),并且這種方法只適用于處理機(jī)和存儲(chǔ)器資源,對(duì)其他資源,此法不宜使用。
破壞循環(huán)等待條件
采用資源順序分配法可破壞該條件。這種分配方法的基本思想是:把系統(tǒng)的全部資源分成多個(gè)層次,一個(gè)進(jìn)程得到某一層的一個(gè)資源后,它只能再_請(qǐng)較高一層的資源;當(dāng)一個(gè)進(jìn)程要釋放某層的一個(gè)資源時(shí),必須先釋放所占有的較高層的資源;當(dāng)一個(gè)進(jìn)程獲得了某一層的一個(gè)資源后,它想再申請(qǐng)?jiān)搶又械牧硪粋€(gè)資源,就必須先釋放在該層中巳占有的資源?;蛘哒f,進(jìn)程釋放資源的順序是按照中請(qǐng)資源的相反順序進(jìn)行的。這樣可以預(yù)防循環(huán)等待現(xiàn)象的發(fā)生,因此不會(huì)發(fā)生死鎖。使用該方法要特別注意的問題是對(duì)資源所處層次的安排。在通常情況下,把各進(jìn)程經(jīng)常用到的、比較普遍的資源安排在較低的層次上,把重要且相對(duì)匱乏的資源安排在較高的層次上,以便實(shí)現(xiàn)對(duì)各資源的最大限度的利用。該方法相對(duì)于前面介紹的方法,在資源利用率和系統(tǒng)吞吐量上都有明顯的改善。但也存在一些缺陷。
(1)低層次的資源必須在進(jìn)程請(qǐng)求分配髙層次的資源之前提前申請(qǐng),這對(duì)于暫時(shí)不需使用的低層次資源來說,會(huì)因空閑等待而產(chǎn)生浪費(fèi)。
(2)各類設(shè)備的資源層次一經(jīng)設(shè)定,便不能經(jīng)常隨意改動(dòng),這就限制了新類型設(shè)備的增加。
(3)各資源的層次是按照大多數(shù)進(jìn)程使用資源的順序設(shè)置的。對(duì)于資源使用與此層次相閃配的進(jìn)程,資源能得到有效的利用,否則,資源的浪費(fèi)現(xiàn)象將仍然存在。
聲明:本網(wǎng)站尊重并保護(hù)知識(shí)產(chǎn)權(quán),根據(jù)《信息網(wǎng)絡(luò)傳播權(quán)保護(hù)條例》,如果我們轉(zhuǎn)載的作品侵犯了您的權(quán)利,請(qǐng)?jiān)谝粋€(gè)月內(nèi)通知我們,我們會(huì)及時(shí)刪除。
蜀ICP備2020033479號(hào)-4 Copyright ? 2016 學(xué)習(xí)鳥. 頁面生成時(shí)間:3.071秒