2011-09-30 96 views
4

我開始在隊列上工作的一羣線程,我想在發送SIGINT(Ctrl + C)時殺死它們。處理這個問題的最好方法是什麼?Python如何殺死阻塞隊列中的線程信號?

targets = Queue.Queue() 
threads_num = 10 
threads = [] 

for i in threads_num: 
    t = MyThread() 
    t.setDaemon(True) 
    threads.append(t) 
    t.start() 

targets.join() 

回答

3

是不是按Ctrl +çSIGINT

無論如何,你可以安裝一個處理程序,適當的信號,並在處理程序:

  • 設置指示工作人員退出,並確保他們定期檢查
  • 或放一個全局標誌隊列10個關機標記,並有工人離開時,他們跳出這個神奇的令牌
  • 或一組指示主線程來推動這些令牌標誌,確保主線程檢查該標誌

等。主要取決於您打斷的應用程序的結構。

+0

對!編輯SIGINT – gbr

+0

+1用於使用他們正在等待的隊列向所有線程發送自殺請求。 –

2

一種方式來做到這一點是安裝一個信號處理程序SIGTERM直接調用os._exit(signal.SIGTERM)。但是,除非您指定Queue.get的可選timeout參數,否則在get方法返回之後,信號處理函數將不會運行。 (這是完全沒有記錄的;我自己發現了。)因此,您可以指定sys.maxint作爲超時,並將您的Queue.get調用置於純循環的重試循環中以解決此問題。

+2

是的,必須指定'timeout = sys.maxint'到'Queue.get'是。 –

0

爲什麼不設置隊列上任何操作的超時?然後,您的線程可以定期檢查是否必須通過檢查是否引發事件來完成。

-1

我試圖通過清空隊列KeyboardInterrupt並讓線程正常停止自己來解決問題。

我不知道這是處理這個問題的最好方法,但很簡單,很乾淨。

targets = Queue.Queue() 
threads_num = 10 
threads = [] 

for i in threads_num: 
    t = MyThread() 
    t.setDaemon(True) 
    threads.append(t) 
    t.start() 

while True: 
    try: 
     # If the queue is empty exit loop 
     if self.targets.empty() is True: 
      break 

    # KeyboardInterrupt handler 
    except KeyboardInterrupt: 
     print "[X] Interrupt! Killing threads..." 
     # Substitute the old queue with a new empty one and exit loop 
     targets = Queue.Queue() 
     break 

# Join every thread on the queue normally 
targets.join() 
+0

文檔說明您不能在隊列上安全地使用.empty()。 – zindel

+0

@zindel是的我發現它困難的方式 – gbr

5

如果你不感興趣,讓其他線程正常關閉,只需啓動它們在守護進程模式,敷在終止線程加入隊列中。

這樣,您可以使用線程的join方法 - 它支持超時並且不會阻止異常 - 而不必等待隊列的join方法。

換句話說,做這樣的事情:

term = Thread(target=someQueueVar.join) 
term.daemon = True 
term.start() 
while (term.isAlive()): 
    term.join(3600) 

現在,按Ctrl + C將終止MainThread於是Python解釋器硬殺死所有線程標記爲「守護」。請注意,這意味着您必須爲所有其他線程設置「Thread.daemon」,或者通過捕獲正確的異常(KeyboardInterrupt或SystemExit)併爲它們退出而做任何需要的操作來優雅地關閉它們。

還請注意,您絕對需要將號碼傳遞給term.join(),否則它也會忽略所有例外。不過,您可以選擇一個任意高的數字。