寫了個多線程的python腳本,結果居然死鎖了。調試了一整天才找到原因,是我使用queue的錯誤導致的。
為了說明問題,下面是一個簡化版的代碼。注意,這個代碼是錯的,后面會說原因和解決辦法。
import Queue import threading queue = Queue.Queue() def test(q): while True: if q.qsize() != 0: d = q.get() print d else: break def main(): global queue n = 100 for i in range(66): queue.put(i) threads = [] for i in range(n) threads.append(threading.Thread(target=test, args = (queue,))) for i in range(n): threads[i].start() for i in range(n): threads[i].join()
上面這個代碼是會造成死鎖的。原因就在下面這一小段。
while True: if q.qsize() != 0: d = q.get()
由於有多個線程同時運行此段代碼,所以隊列q是各個線程共享的。
如果在q只剩一個數據的時候,有3個線程都運行到if q.qsize() != 0:,那么這3個線程都會滿足此條件。從而繼續運行。
然后,在d = q.get()處,只有一個線程能夠取到數據,此后隊列為空,另外兩個線程無法取得數據,從而鎖死在此處。
解決方法:加鎖
import Queue import threading queue = Queue.Queue() mutex = threading.Lock() def test(q): global mutex while True: mutex.acquire() if q.qsize() != 0: d = q.get() mutex.release() print d else: mutex.release() break def main(): global queue n = 100 for i in range(66): queue.put(i) threads = [] for i in range(n) threads.append(threading.Thread(target=test, args = (queue,))) for i in range(n): threads[i].start() for i in range(n): threads[i].join()