线程忽略KeyboardInterrupt异常

时间:2010-09-24 14:48:23

标签: python multithreading events exception keyboardinterrupt

我正在运行这个简单的代码:

import threading, time

class reqthread(threading.Thread):    
    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

实际上python线程会忽略我的 Ctrl + C 键盘中断而不会打印Received Keyboard Interrupt。为什么?这段代码有什么问题?

5 个答案:

答案 0 :(得分:58)

尝试

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导致线程在主进程结束时终止。

答案 1 :(得分:9)

总结the comments中建议的更改,以下内容适用于我:

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()

答案 2 :(得分:4)

轻微修改ubuntu的解决方案。

按照Eric的建议删除tread.daemon = True并用signal.pause()替换sleep循环:

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'

答案 3 :(得分:0)

我的(hacky)解决方案是像这样修补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

答案 4 :(得分:0)

try ... except放在每个帖子中,并将signal.pause()放在 true main()中。

留意{ {3}}但是。我猜这就是Python默认不解决ctrl-C的原因。