1. 前言
操作系統(tǒng)中的很多資源都是多個進程或者多個線程之間共享的,例如同一個文件,可能同時會被多個程序讀寫?;蛘呤且粋€內(nèi)存變量,存在同時被多個線程修改的可能。如果資源能夠不能以合理的順序訪問就可能產(chǎn)生沖突,這種競爭資源的現(xiàn)象可能造成阻塞,引發(fā)死鎖。
2. 死鎖
面試官提問: 談談操作系統(tǒng)中的死鎖是什么,產(chǎn)生死鎖的條件是什么?有什么解決方案?
題目解析:
這是一種經(jīng)典的提問方法,對于一個問題 A,面試官提出問題 A 的定義,候選人闡明定義之后,才能確保候選人和面試官彼此討論的是同一個問題,而不是牛頭不對馬嘴。其次才是討論這個問題的起源,在提出問題之后,當然需要給出解決方案,解決方案的優(yōu)劣可以反應候選人對面試題目的理解程度。
2.1 死鎖定義
死鎖(DeadLock)可以發(fā)生在多個進程之間或者是多個線程之間,本文以線程作為觀察對象。那么死鎖的定義就是多個線程競爭同一個資源造成的僵局,如果沒有外力推動,這種僵局會一直持續(xù)下去,線程的狀態(tài)都無法繼續(xù)推進。例如操作系統(tǒng)中有兩個線程,分別是線程 A 和線程 B,線程 A 按照先獲取鎖 a 再獲取鎖 b 的順序占用鎖的資源,線程 B 按照先獲取鎖 b 再獲取鎖 a 的順序占用鎖。
線程 A 占用了鎖 a,線程 B 占用了鎖 b,線程 A 需要占用鎖 b 之后才能釋放鎖 a,線程 B 則需要占用鎖 a 之后才能釋放鎖 b,兩個線程都進入了等待對方釋放鎖的狀態(tài),造成死鎖。
2.2 死鎖條件
造成進程或者線程死鎖有四個必要條件:
(1)互斥條件:進程(線程)對于分配的資源有排他性,排他性是指一個資源在同一段時間內(nèi)只能被一個進程(線程)占用。
(2)請求和保持條件:進程(線程)因為請求資源導致阻塞時,對于已經(jīng)獲得資源不會主動釋放。通俗來說就是已有的資源不會放棄,沒有的資源會持續(xù)請求。
(3)不可剝奪條件:進程(線程)在獲得的資源沒有使用完成之前,資源不能被剝奪,只能等進程(線程)主動釋放。
(4)循環(huán)等待條件:所有等待的進程(線程)在發(fā)生死鎖時,都會形成一個死循環(huán)環(huán)路,這也是造成死鎖的直接原因。
2.3 死鎖解決方案
死鎖的解決方案就是從產(chǎn)生死鎖的必要條件入手,如果不滿足必要條件,那么就失去了發(fā)生死鎖的可能性。還是以線程為例,給出死鎖的解決方案:
(1)破壞請求條件:一次性給線程分配所有的資源,例如上述案例直接給線程 A 分配鎖 a 和鎖 b。
(2)破壞保持條件:只要存在任何一個資源不能被分配,已有被分配的資源也不能保持。例如上述案例中線程 A 不能獲得鎖 b,那么需要主動釋放鎖 a。
(3)破壞不可剝奪條件:只要存在任何一個資源不能被分配,已有被分配的資源可以被強制釋放。
(4)破壞循環(huán)等待條件:所有的線程按照提前指定的順序請求資源,釋放資源的順序剛好相反。
避免死鎖的經(jīng)典算法有銀行家算法,我們把操作系統(tǒng)比喻成銀行家,操作系統(tǒng)管理的資源就是銀行中的資金,進程(線程)就是顧客,獲取資源的過程就是向銀行家索要貸款的過程,線程在獲取資源前需要申明自己需要的每種資源的最大數(shù)量,操作系統(tǒng)計算在分配這些資源之后,是否會讓系統(tǒng)處于不安全的狀態(tài)。總結(jié)來看,銀行家算法是一個動態(tài)判斷死鎖的算法。
3. 小結(jié)
本章節(jié)介紹了死鎖的定義、產(chǎn)生原因以及典型的解決方案,與死鎖對應的還有活鎖的概念,活鎖在嘗試獲取資源失敗之后,會主動釋放自己持有的鎖,然后再重試整個拿鎖流程。與活鎖對應的是進程的饑餓,如果一個進程永遠拿不到需要的資源,服務會一直阻塞,被比喻為饑餓。關(guān)于死鎖,還會涉及到編程實戰(zhàn)中如何避免死鎖以及死鎖的檢測條件,候選人可以自行深入探討。