2011-09-30 50 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(),否则它也会忽略所有例外。不过,您可以选择一个任意高的数字。