避免死鎖的方法:
當兩個執行緒互相等待對方釋放資源時,就會發生死鎖。 Python 解釋器沒有監測,也不會主動採取措施來處理死鎖情況,所以在進行多執行緒程式設計時應該採取措施避免死鎖。
一旦出現死鎖,整個程式既不會發生任何異常,也不會給予任何提示,只是所有執行緒都處於阻塞狀態,無法繼續。
死鎖是很容易發生的,尤其是在系統中出現多個同步監視器的情況下,如下程序將會出現死鎖:
import threading import time class A: def __init__(self): self.lock = threading.RLock() def foo(self, b): try: self.lock.acquire() print("当前线程名: " + threading.current_thread().name\ + " 进入了A实例的foo()方法" ) # ① time.sleep(0.2) print("当前线程名: " + threading.current_thread().name\ + " 企图调用B实例的last()方法") # ③ b.last() finally: self.lock.release() def last(self): try: self.lock.acquire() print("进入了A类的last()方法内部") finally: self.lock.release() class B: def __init__(self): self.lock = threading.RLock() def bar(self, a): try: self.lock.acquire() print("当前线程名: " + threading.current_thread().name\ + " 进入了B实例的bar()方法" ) # ② time.sleep(0.2) print("当前线程名: " + threading.current_thread().name\ + " 企图调用A实例的last()方法") # ④ a.last() finally: self.lock.release() def last(self): try: self.lock.acquire() print("进入了B类的last()方法内部") finally: self.lock.release() a = A() b = B() def init(): threading.current_thread().name = "主线程" # 调用a对象的foo()方法 a.foo(b) print("进入了主线程之后") def action(): threading.current_thread().name = "副线程" # 调用b对象的bar()方法 b.bar(a) print("进入了副线程之后") # 以action为target启动新线程 threading.Thread(target=action).start() # 调用init()函数 init()
執行上面程序,將會看到如圖1 所示的效果。
圖1 死鎖效果
從圖1 可以看出,程式既無法向下執行,也不會拋出任何異常,就一直「僵持」著。究其原因,是因為上面程式中 A 物件和 B 物件的方法都是執行緒安全的方法。
程式中有兩個執行緒執行,副執行緒的執行緒執行體是 action() 函數,主執行緒的執行緒執行體是 init() 函數(主程式呼叫了 init() 函數)。其中在 action() 函數中讓 B 物件呼叫 bar() 方法,而在 init() 函數中讓 A 物件呼叫 foo() 方法。
圖1 顯示action() 函數先執行,呼叫了B 物件的bar() 方法,在進入bar() 方法之前,該執行緒對B 物件的Lock 加鎖(當程式執行到② 號程式碼時,副線程暫停0.2s);CPU 切換到執行另一個線程,讓A 物件執行foo() 方法,所以看到主線程開始執行A 實例的foo() 方法,在進入foo() 方法之前,此執行緒對A 物件的Lock 加鎖(當程式執行到① 號程式碼時,主執行緒也暫停0.2s)。
接下來副線程會先醒過來,繼續向下執行,直到執行到④ 號程式碼處希望呼叫A 物件的last() 方法(在執行該方法之前,必須先對A 物件的Lock加鎖),但此時主執行緒正保持著A 物件的Lock 的鎖定,所以副執行緒被阻塞。
接下來主執行緒應該也醒過來了,繼續向下執行,直到執行到③ 號程式碼處希望呼叫B 物件的last() 方法(在執行該方法之前,必須先對B 物件的Lock 加鎖),但此時副執行緒並沒有釋放對B 物件的Lock 的鎖定。
至此,就出現了主執行緒保持著A 物件的鎖,等待對B 物件加鎖,而副執行緒保持著B物件的鎖,等待對A 物件加鎖,兩個執行緒互相等待對方先釋放鎖,所以就出現了死鎖。
死鎖是不應該在程式中出現的,在編寫程式時應該盡量避免出現死鎖。 下面有幾種常見的方式用來解決死鎖問題:
#避免多次鎖定。盡量避免同一個執行緒對多個 Lock 進行鎖定。例如上面的死鎖程序,主線程要對 A、B 兩個物件的 Lock 進行鎖定,副線程也要對 A、B 兩個物件的 Lock 進行鎖定,這就埋下了導致死鎖的隱患。
具有相同的加鎖順序。如果多個執行緒需要對多個 Lock 進行鎖定,則應該保證它們以相同的順序請求加鎖。例如上面的死鎖程序,主執行緒先對 A 物件的 Lock 加鎖,再對 B 物件的 Lock 加鎖;而副執行緒則先對 B 物件的 Lock 加鎖,再對 A 物件的 Lock 加鎖。這種加鎖順序很容易形成嵌套鎖定,進而導致死鎖。如果讓主執行緒、副執行緒依照相同的順序加鎖,就可以避免這個問題。
使用定時鎖定。程式在呼叫 acquire() 方法加鎖時可指定 timeout 參數,該參數指定超過 timeout 秒後會自動釋放對 Lock 的鎖定,這樣就可以解開死鎖了。
死鎖偵測。死鎖檢測是一種依靠演算法機制來實現的死鎖預防機制,它主要是針對那些不可能實現按序加鎖,也不能使用定時鎖的場景的。
以上是如何避免死鎖?的詳細內容。更多資訊請關注PHP中文網其他相關文章!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

DVWA
Damn Vulnerable Web App (DVWA) 是一個PHP/MySQL的Web應用程序,非常容易受到攻擊。它的主要目標是成為安全專業人員在合法環境中測試自己的技能和工具的輔助工具,幫助Web開發人員更好地理解保護網路應用程式的過程,並幫助教師/學生在課堂環境中教授/學習Web應用程式安全性。 DVWA的目標是透過簡單直接的介面練習一些最常見的Web漏洞,難度各不相同。請注意,該軟體中

EditPlus 中文破解版
體積小,語法高亮,不支援程式碼提示功能

SecLists
SecLists是最終安全測試人員的伙伴。它是一個包含各種類型清單的集合,這些清單在安全評估過程中經常使用,而且都在一個地方。 SecLists透過方便地提供安全測試人員可能需要的所有列表,幫助提高安全測試的效率和生產力。清單類型包括使用者名稱、密碼、URL、模糊測試有效載荷、敏感資料模式、Web shell等等。測試人員只需將此儲存庫拉到新的測試機上,他就可以存取所需的每種類型的清單。

WebStorm Mac版
好用的JavaScript開發工具