2010-09-24 175 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的問題。