我正在嘗試編寫一個正在偵聽套接字,stdin和從文件描述符中讀取的unix客戶端程序。我將這些任務中的每一個分配給單獨的線程,並使用同步隊列和信號成功地與「主」應用程序通信。問題是,當我想關閉這些子線程時,它們都是輸入阻塞的。此外,線程無法在線程中註冊信號處理程序,因爲在Python中只允許執行的主線程執行此操作。優雅地終止Python線程
有什麼建議嗎?
我正在嘗試編寫一個正在偵聽套接字,stdin和從文件描述符中讀取的unix客戶端程序。我將這些任務中的每一個分配給單獨的線程,並使用同步隊列和信號成功地與「主」應用程序通信。問題是,當我想關閉這些子線程時,它們都是輸入阻塞的。此外,線程無法在線程中註冊信號處理程序,因爲在Python中只允許執行的主線程執行此操作。優雅地終止Python線程
有什麼建議嗎?
沒有好辦法解決這個問題,特別是當線程阻塞時。
我有一個類似的問題(Python: How to terminate a blocking thread),我能阻止我的線程的唯一方法是關閉底層連接。這導致阻塞的線程升起和異常,然後讓我檢查停止標誌並關閉。
示例代碼:
class Example(object):
def __init__(self):
self.stop = threading.Event()
self.connection = Connection()
self.mythread = Thread(target=self.dowork)
self.mythread.start()
def dowork(self):
while(not self.stop.is_set()):
try:
blockingcall()
except CommunicationException:
pass
def terminate():
self.stop.set()
self.connection.close()
self.mythread.join()
另外一點需要注意的是常用阻塞操作一般提供了一個暫停。如果你有這個選擇,我會考慮使用它。我最後的評論是,你總是可以設置線程deamonic,
從是pydoc:
線程可以被標記爲「守護線程」。這個標誌的意義在於,只有守護進程線程退出時,整個Python程序纔會退出。初始值是從創建線程繼承的。該標誌可以通過守護進程屬性設置。
請注意,觸摸另一個線程正在使用的filedescriptor是不安全的,它可能導致比其他線程中的異常更糟糕的事情。您應該真正使用非阻塞I/O。 – 2011-06-15 14:52:17
+1我100%同意,但有些時候你不能......;( – Nix 2011-06-15 14:53:02
不幸的是,雖然很少,當它是你正在操作的filedescriptors時(真正有問題的情況是阻止沒有這是一個不錯的解決方法:P) – 2011-06-15 14:54:54
見這些問題的答案:
Python SocketServer
How to exit a multithreaded program?
基本上,通過使用select()
有超時檢查套接字的可讀性recv()
不阻止,並查詢一個退出標誌時select()
超時。
這是一個不錯的解決方案,但我希望有一個更有說服力的方法來實現這一點,而不必經常循環。這也會導致延遲,只要我真的想殺死線程while它等待選擇超時。 – George 2011-06-15 15:15:05
這就是線程的世界...... – theorifice 2016-10-25 12:05:19
此外,線程不能註冊信號處理程序
信號殺線程是潛在的恐怖,特別是在C,尤其是如果分配存儲器中作爲螺紋的一部分,因爲它不會被釋放當特定的線程死亡時(因爲它屬於進程的堆)。 C中沒有垃圾回收,所以如果該指針超出範圍,它就超出了範圍,內存仍然分配。所以只需要小心一點 - 只有在C中這樣做才能殺死所有線程並結束進程,從而將內存交還給操作系統 - 例如,從線程池中添加和刪除線程會給你一個內存泄漏。
問題是,當我想關閉這些子線程時,它們都是輸入阻塞。
有趣的是,最近我一直在用同樣的東西打架。解決方法是從字面上不會在沒有超時的情況下發出阻止呼叫。因此,例如,你想要什麼理想的是:
def threadfunc(running):
while running:
blockingcall(timeout=1)
其中運行從控制線程過去了 - 我從來沒有用過線程,但我已經使用多以及與此你真正需要傳遞一個Event()
對象,檢查is_set()
。但是你要求設計模式,這是基本的想法。
然後,當你想這個線程結束,我們可以運行:
running.clear()
mythread.join()
,然後你的主線程應該讓你的客戶的線程來處理它的最後一次通話,並返回,整個程序更好地摺疊起來。
如果您在沒有超時的情況下阻止呼叫,您會做什麼?如果需要,可以使用異步選項,並進入休眠狀態(如調用任何方法來暫停線程一段時間,以免不旋轉)。沒有別的辦法。
什麼樣的線程?有幾個庫提供了線程功能。 – Blender 2011-06-15 14:47:25
不幸的是,當使用單獨的(POSIX)線程進行連接時,這只是冰山一角。請考慮使用非阻塞I/O(例如,使用Twisted)。 – 2011-06-15 14:53:19
線程需要自行終止(或被告知這樣做)。你可以讓他們不被阻止,所以他們可以退出,如果信號? (polling或其他) – 2011-06-15 14:54:09