2010-09-24 126 views
40

我跑我这简单的代码:线程忽略KeyboardInterrupt异常

import threading, time 

class reqthread (threading.Thread): 
    def __init__ (self): 
    threading.Thread.__init__(self) 

    def run (self): 
    for i in range(0,10): 
     time.sleep(1) 
     print '.' 

try: 
    thread=reqthread() 
    thread.start() 
except (KeyboardInterrupt, SystemExit): 
    print '\n! Received keyboard interrupt, quitting threads.\n' 

但是当我运行它,它打印

$ python prova.py 
` 
. 
. 
^C. 
. 
. 
. 
. 
. 
. 
. 
Exception KeyboardInterrupt in <module 'threading' from '/usr/lib/python2.6/threading.pyc'> ignored 
` 

其实蟒蛇线程无视我按Ctrl +Ç键盘中断并不打印Received Keyboard Interrupt。为什么?这段代码有什么问题?

回答

50

尝试

try: 
    thread=reqthread() 
    thread.daemon=True 
    thread.start() 
    while True: time.sleep(100) 
except (KeyboardInterrupt, SystemExit): 
    print '\n! Received keyboard interrupt, quitting threads.\n' 

没有调用time.sleep,主要工艺是太早跳出try...except块,所以KeyboardInterrupt没有被捕获。我的第一个想法是使用thread.join,但似乎阻止主进程(忽略KeyboardInterrupt),直到thread完成。

thread.daemon=True会导致主进程结束时线程终止。

+4

我相信'join'上的超时,即'while thread.isAlive:thread.join(5)'也可以使主线程响应异常。 – 2012-09-11 19:51:03

+11

'thread.daemon = True'实际上并不推荐,因为它不允许线程清理掉任何留下的资源...... – 2013-09-29 14:47:59

7

总结推荐的变化thecomments,下面的工作很适合我:

try: 
    thread = reqthread() 
    thread.start() 
    while thread.isAlive(): 
    thread.join(1) # not sure if there is an appreciable cost to this. 
except (KeyboardInterrupt, SystemExit): 
    print '\n! Received keyboard interrupt, quitting threads.\n' 
    sys.exit() 
+0

在“while thread.isAlive”中反复调用“thread.join()” ():“好东西/有关系吗? – DevPlayer 2016-09-15 13:39:00

+0

我个人不知道;可能值得尝试制定一个基准,如果性能对你有用吗? – rattray 2016-09-16 00:43:14

+1

请注意exit()和sys.exit()不一样。建议使用sys.exit()。 – DevPlayer 2016-11-18 01:23:26

0

我(哈克)解决方案是猴子修补Thread.join()这样的:

def initThreadJoinHack(): 
    import threading, thread 
    mainThread = threading.currentThread() 
    assert isinstance(mainThread, threading._MainThread) 
    mainThreadId = thread.get_ident() 
    join_orig = threading.Thread.join 
    def join_hacked(threadObj, timeout=None): 
    """ 
    :type threadObj: threading.Thread 
    :type timeout: float|None 
    """ 
    if timeout is None and thread.get_ident() == mainThreadId: 
     # This is a HACK for Thread.join() if we are in the main thread. 
     # In that case, a Thread.join(timeout=None) would hang and even not respond to signals 
     # because signals will get delivered to other threads and Python would forward 
     # them for delayed handling to the main thread which hangs. 
     # See CPython signalmodule.c. 
     # Currently the best solution I can think of: 
     while threadObj.isAlive(): 
     join_orig(threadObj, timeout=0.1) 
    else: 
     # In all other cases, we can use the original. 
     join_orig(threadObj, timeout=timeout) 
    threading.Thread.join = join_hacked 
2

稍作修改的Ubuntu解决方案。

卸下tread.daemon =真所建议由Eric和更换通过signal.pause休眠循环():

import signal 
try: 
    thread=reqthread() 
    thread.start() 
    signal.pause() # instead of: while True: time.sleep(100) 
except (KeyboardInterrupt, SystemExit): 
    print '\n! Received keyboard interrupt, quitting threads.\n' 
+1

不错 - 但不幸的是,在Windows上不支持 – 2016-08-25 09:36:35

0

把在每个线程try ... except,并且也是在signal.pause()main()作品我。但是,请注意import lock。我猜这就是为什么Python默认情况下不能解决ctrl-C的问题。