死锁产生的原因及条件、如何避免死锁
一、死鎖的定義
是指兩個或兩個以上的進程在執(zhí)行過程中,由于競爭資源或者由于彼此通信而造、成的一種阻塞的現(xiàn)象,若無外力作用,它們都將無法推進下去。此時稱系統(tǒng)處于死鎖狀態(tài)或系統(tǒng)產(chǎn)生了死鎖,這些永遠在互相等待的進程稱為死鎖進程。
?
二、死鎖產(chǎn)生的原因
(1)因為系統(tǒng)資源不足。
(2)進程運行推進的順序不合適。
(3)資源分配不當(dāng)?shù)取?/span>
如果系統(tǒng)資源充足,進程的資源請求都能夠得到滿足,死鎖出現(xiàn)的可能性就很低,否則
就會因爭奪有限的資源而陷入死鎖。其次,進程運行推進順序與速度不同,也可能產(chǎn)生死鎖。
三、死鎖產(chǎn)生的條件
(1)互斥條件:一個資源每次只能被一個進程使用。
(2)請求與保持條件:一個進程因請求資源而阻塞時,對已獲得的資源保持不放。
(3)不剝奪條件:進程已獲得的資源,在末使用完之前,不能強行剝奪。
(4)循環(huán)等待條件:若干進程之間形成一種頭尾相接的循環(huán)等待資源關(guān)系。
四、如何避免死鎖
?
?????? 在有些情況下死鎖是可以避免的。三種用于避免死鎖的技術(shù):
加鎖順序
當(dāng)多個線程需要相同的一些鎖,但是按照不同的順序加鎖,死鎖就很容易發(fā)生。
如果能確保所有的線程都是按照相同的順序獲得鎖,那么死鎖就不會發(fā)生。看下面這個例子:
Thread 1:
? lock A
? lock B
?
Thread 2:
?? wait for A
?? lock C (when A locked)
?
Thread 3:
?? wait for A
?? wait for B
?? wait for C
如果一個線程(比如線程3)需要一些鎖,那么它必須按照確定的順序獲取鎖。它只有獲得了從順序上排在前面的鎖之后,才能獲取后面的鎖。
例如,線程2和線程3只有在獲取了鎖A之后才能嘗試獲取鎖C(譯者注:獲取鎖A是獲取鎖C的必要條件)。因為線程1已經(jīng)擁有了鎖A,所以線程2和3需要一直等到鎖A被釋放。然后在它們嘗試對B或C加鎖之前,必須成功地對A加了鎖。
按照順序加鎖是一種有效的死鎖預(yù)防機制。但是,這種方式需要你事先知道所有可能會用到的鎖(譯者注:并對這些鎖做適當(dāng)?shù)呐判?/span>),但總有些時候是無法預(yù)知的。
?
加鎖時限
另外一個可以避免死鎖的方法是在嘗試獲取鎖的時候加一個超時時間,這也就意味著在嘗試獲取鎖的過程中若超過了這個時限該線程則放棄對該鎖請求。若一個線程沒有在給定的時限內(nèi)成功獲得所有需要的鎖,則會進行回退并釋放所有已經(jīng)獲得的鎖,然后等待一段隨機的時間再重試。這段隨機的等待時間讓其它線程有機會嘗試獲取相同的這些鎖,并且讓該應(yīng)用在沒有獲得鎖的時候可以繼續(xù)運行(譯者注:加鎖超時后可以先繼續(xù)運行干點其它事情,再回頭來重復(fù)之前加鎖的邏輯)。
以下是一個例子,展示了兩個線程以不同的順序嘗試獲取相同的兩個鎖,在發(fā)生超時后回退并重試的場景:
?
Thread 1 locks A
Thread 2 locks B
?
Thread 1 attempts to lock B but is blocked
Thread 2 attempts to lock A but is blocked
?
Thread 1's lock attempt on B times out
Thread 1 backs up and releases A as well
Thread 1 waits randomly (e.g. 257 millis) before retrying.
?
Thread 2's lock attempt on A times out
Thread 2 backs up and releases B as well
Thread 2 waits randomly (e.g. 43 millis) before retrying.
在上面的例子中,線程2比線程1早200毫秒進行重試加鎖,因此它可以先成功地獲取到兩個鎖。這時,線程1嘗試獲取鎖A并且處于等待狀態(tài)。當(dāng)線程2結(jié)束時,線程1也可以順利的獲得這兩個鎖(除非線程2或者其它線程在線程1成功獲得兩個鎖之前又獲得其中的一些鎖)。
需要注意的是,由于存在鎖的超時,所以我們不能認為這種場景就一定是出現(xiàn)了死鎖。也可能是因為獲得了鎖的線程(導(dǎo)致其它線程超時)需要很長的時間去完成它的任務(wù)。
此外,如果有非常多的線程同一時間去競爭同一批資源,就算有超時和回退機制,還是可能會導(dǎo)致這些線程重復(fù)地嘗試但卻始終得不到鎖。如果只有兩個線程,并且重試的超時時間設(shè)定為0到500毫秒之間,這種現(xiàn)象可能不會發(fā)生,但是如果是10個或20個線程情況就不同了。因為這些線程等待相等的重試時間的概率就高的多(或者非常接近以至于會出現(xiàn)問題)。
(譯者注:超時和重試機制是為了避免在同一時間出現(xiàn)的競爭,但是當(dāng)線程很多時,其中兩個或多個線程的超時時間一樣或者接近的可能性就會很大,因此就算出現(xiàn)競爭而導(dǎo)致超時后,由于超時時間一樣,它們又會同時開始重試,導(dǎo)致新一輪的競爭,帶來了新的問題。)
?
總結(jié)
以上是生活随笔為你收集整理的死锁产生的原因及条件、如何避免死锁的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python客户端软件开发_用 Pyth
- 下一篇: 费曼:微积分是上帝的语言 | 书摘