死鎖產(chǎn)生的原因以及舉例登失,如何解決
何為死鎖: 多進(jìn)程或多線程中,因爭奪資源而造成一種互相等待的現(xiàn)象,若無外部處理作用殿托,她們將無限等待下去
-
死鎖產(chǎn)生的原因:
- 系統(tǒng)資源不足
- 進(jìn)程或線程推進(jìn)的順序不恰當(dāng)
- 資源分配不當(dāng)
-
死鎖形成條件
- 互斥條件:進(jìn)程在某一時間內(nèi)獨占資源
- 請求與保持條件:一個進(jìn)程因請求資源而阻塞,對獲得資源保持不放
- 不剝奪條件:進(jìn)程未使用完資源剧蚣,不得強制剝奪
- 循環(huán)等待條件:各種進(jìn)程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系
-
常見死鎖舉例
- 單線程忘記釋放鎖支竹,下次請求時就會一直等待
解決:確保對應(yīng)的釋放鎖
- 單線程忘記釋放鎖支竹,下次請求時就會一直等待
void data_process()
{
lock();
if(/error happen/)
{
return;
}
unlock();
}
```
- 單線程重復(fù)申請鎖
解決:
void sub_fun()
{
lock();
doingsometh();
unclog();
}
void data_process()
{
lock()
sub_fun();
unlock();
}
- 多線程多鎖申請
void thread_process1()
{
lock(a);
lock(b);
dosometh();
unlock(b);
unlock(a);
}
void thread_process2()
{
lock(b);
lock(a);
dosometh();
unlock(a);
unlock(b);
}
線程獲取a資源后旋廷,CPU切換到線程2去獲取b資源,并且線程2等待獲取a資源礼搁,這個時候線程1去獲取b資源饶碘, 由于線程1獲取了a資源還沒釋放,線程2等待馒吴, 線程2獲取了b資源也沒釋放扎运,導(dǎo)致線程1的等待,造成兩個線程相互等待饮戳,引起死鎖
- 環(huán)形死鎖
多個線程申請鎖的順序形成相互依賴的環(huán)形
A-B-C-D-A;
- 針對3豪治,4兩個實例如何解決呢?
- 注意加鎖順序
當(dāng)多個線程需要相同的一些鎖扯罐,但是按照不同的順序加鎖负拟,死鎖就很容易產(chǎn)生,如實例3.
弊端如果能確保線程都是按照相同的順序獲得鎖歹河,那么死鎖就不會發(fā)生了
- 注意加鎖順序
加鎖時限
以上1方法的前提是實現(xiàn)知道可能會用到的鎖掩浙,但實際有時候是無法預(yù)知的
嘗試獲取鎖的時候設(shè)一個超時時間,如果超過時間启泣,就釋放自己所獲得的鎖(這個時候有可能死鎖的存在涣脚,所以釋放自己獲得的鎖)過一段時間重試
弊端 如果獲取資源的線程執(zhí)行時間較長會導(dǎo)致資源不釋放,那么另外的線程獲取資源時超時的幾率就很大 導(dǎo)致重試寥茫。另外有很多線程都依賴相同鎖時遣蚀,就算有超時和回退,還是會導(dǎo)致這些線程重復(fù)的嘗試但卻始終得不到鎖纱耻。死鎖檢測
死鎖檢測是一個更好的死鎖預(yù)防機制芭梯,它主要針對那些不可能實現(xiàn)按序加鎖并且鎖超時也不可行的場景。
每當(dāng)一個線程獲取了鎖弄喘,會在線程和鎖相關(guān)的數(shù)據(jù)結(jié)構(gòu)中將其記下玖喘。除此之外,每當(dāng)有線程請求鎖蘑志,也需要記錄在這個數(shù)據(jù)結(jié)構(gòu)中累奈。
當(dāng)一個線程請求鎖失敗時,這個線程可以遍歷鎖關(guān)系圖是否有死鎖發(fā)生急但。這個檢測算法就比較復(fù)雜了澎媒。
如果檢測到確有死鎖,那么釋放所有鎖波桩,回退戒努,并且等待一段隨機的時間重試。類似超時機制镐躲,不過這中case是在死鎖確實發(fā)生時執(zhí)行储玫,而不是因為加鎖請求超時侍筛。