在 Python 中,Condition
?對象用于線程同步,其?wait()
?方法用于釋放鎖并阻塞線程,直到被其他線程喚醒。使用不當可能導致死鎖、虛假喚醒或邏輯錯誤。以下是常見問題及修復方案:
常見問題與修復方案
1. 未檢查條件(虛假喚醒)
問題:
wait()
?可能被虛假喚醒(即使未收到?notify()
),若用?if
?檢查條件,喚醒后可能條件仍未滿足。python
with cond:if not resource_ready: # ? 錯誤:應用 while 而非 ifcond.wait()
修復:始終用?
while
?循環檢查條件:python
with cond:while not resource_ready: # ? 正確:循環檢查條件cond.wait()
2. 未在持有鎖時調用?wait()
問題:調用?
wait()
?前未獲取關聯鎖,拋出?RuntimeError
。python
cond = threading.Condition() cond.wait() # ? 錯誤:未先獲取鎖
修復:確保在?
with
?塊或?acquire()
/release()
?中調用:python
with cond: # ? 正確:自動獲取/釋放鎖while not ready:cond.wait()
3. 未正確配對?notify()
?和?wait()
問題:
notify()
?未在修改條件的代碼塊中調用,導致信號丟失。python
def producer():resource_ready = True # ? 錯誤:未在鎖內修改條件cond.notify() # 可能錯過喚醒
修復:修改條件和調用?
notify()
?必須在同一鎖內:python
def producer():with cond:resource_ready = True # ? 在鎖內修改條件cond.notify() # 安全喚醒
4. 未使用超時導致永久阻塞
問題:若生產者線程失敗,消費者可能永久阻塞。
修復:為?
wait()
?添加?timeout
?參數并處理超時:python
with cond:while not resource_ready:if not cond.wait(timeout=5.0): # 等待5秒print("Timeout, exiting")break
5. 錯誤使用?notify()
?而非?notify_all()
問題:
notify()
?只喚醒一個線程,若多個線程等待相同條件,可能遺漏喚醒。修復:需要喚醒所有線程時使用?
notify_all()
:python
with cond:resource_ready = Truecond.notify_all() # ? 喚醒所有等待線程
完整正確示例
python
import threading# 共享資源與條件變量 resource_ready = False cond = threading.Condition()def consumer():with cond:while not resource_ready: # 循環檢查條件cond.wait() # 釋放鎖并等待print("Resource is ready!")def producer():with cond:global resource_readyresource_ready = True # 修改條件cond.notify_all() # 喚醒所有等待線程# 啟動線程 threading.Thread(target=consumer).start() threading.Thread(target=producer).start()
關鍵實踐總結
檢查條件:始終用?
while
?循環檢查條件(防虛假喚醒)。鎖的作用域:
wait()
、notify()
?及條件修改必須在同一鎖內。喚醒選擇:
notify()
:喚醒?1 個線程(效率高)。notify_all()
:喚醒?所有線程(避免遺漏)。
超時機制:用?
wait(timeout=seconds)
?防止永久阻塞。資源狀態:條件變量應關聯明確的共享狀態(如?
resource_ready
)。
遵循這些模式可避免?Condition
?的常見陷阱,確保線程安全。