死鎖產生的4個必要條件:
1、互斥:一個資源同一時刻只允許一個線程進行訪問。
2、占有未釋放:一個線程占有資源,且沒有釋放資源。
3、不可搶占:一個已經占有資源的線程無法搶占到其他線程擁有的資源。
4、循環等待:兩個或者兩個以上的線程,本身擁有資源,不釋放資源,並且同時嘗試獲得其他線程所持有的資源,這種資源的申請關系形成一個閉環的鏈條。
死鎖的避免:
關於死鎖的避免,仁者見仁智者見智。
主要還是從造成死鎖的四個條件入手,四個條件不能滿足,就不會死鎖。
以下是我本人的一些方法:
1.線程等待時(wait)給予一個默認的等待時間
2.線程之間資源避免相互申請對方的資源,可以通過一些容器來控制並發,比如blockqueue,等等一些線程安全的容器
3.盡量避免線程在等待的同時申請資源
4.死鎖檢測,一個線程在等待一段時間后還沒有獲得資源就放棄申請。對等待時間進行檢測。
一個死鎖的例子:
# 線程死鎖,在classA和classB相互調用對方的方法,並且相互等待對方釋放資源 class ClassA: def __init__(self): self.lock=threading.RLock() # 得到classA的鎖,試圖得到classB的鎖 def infoA(self, b): self.lock.acquire() time.sleep(10) b.info() self.lock.release() def info(self): self.lock.acquire() print("this is ClassA info") self.lock.release() class ClassB: def __init__(self): self.lock = threading.RLock() # 得到classB的鎖,試圖得到classA的鎖 def infoB(self, a): self.lock.acquire() time.sleep(10) a.info() self.lock.release() def info(self): self.lock.acquire() print("this is ClassB info") self.lock.release() ca=ClassA() cb=ClassB() def funA(): ca.infoA(cb) def funB(): cb.infoB(ca) # 函數調用不是線程,不會死鎖 # funA() # funB() t1=threading.Thread(target=funA).start() t2=threading.Thread(target=funB).start()
說明:
線程 | 狀態 | |||
classA | 獲得classA的鎖,sleep(classA的鎖未釋放) | 申請classB的鎖 | 死鎖 | |
classB | 獲得classB的鎖,sleep(classB的鎖未釋放) | 申請classA的鎖 | 死鎖 | |