Python 线程忽略键盘中断异常

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3788208/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-18 12:45:43  来源:igfitidea点击:

threading ignores KeyboardInterrupt exception

pythonmultithreadingeventsexceptionkeyboardinterrupt

提问by Emilio

I'm running this simple code:

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

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

But when I run it, it prints

但是当我运行它时,它会打印

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

In fact python thread ignore my Ctrl+Ckeyboard interrupt and doesn't print Received Keyboard Interrupt. Why? What is wrong with this code?

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

采纳答案by unutbu

Try

尝试

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

Without the call to time.sleep, the main process is jumping out of the try...exceptblock too early, so the KeyboardInterruptis not caught. My first thought was to use thread.join, but that seems to block the main process (ignoring KeyboardInterrupt) until the threadis finished.

如果没有调用time.sleep,主进程会try...except过早地跳出块,因此KeyboardInterrupt不会被捕获。我的第一个想法是使用thread.join,但这似乎会阻止主进程(忽略 KeyboardInterrupt)直到thread完成。

thread.daemon=Truecauses the thread to terminate when the main process ends.

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

回答by rattray

To summarize the changes recommended in thecomments, the following works well for me:

总结中推荐的变化意见,下面很适合我:

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

回答by Albert

My (hacky) solution is to monkey-patch Thread.join()like this:

我的(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

回答by yaccob

Slight modification of ubuntu's solution.

对 ubuntu 的解决方案稍作修改。

Removing tread.daemon = True as suggested by Eric and replacing the sleeping loop by signal.pause():

按照埃里克的建议删除tread.daemon = True 并通过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'

回答by personal_cloud

Putting the try ... exceptin each thread and also a signal.pause()in truemain()works for me.

try ... except每个线程,也是一个signal.pause()真正main()为我工作。

Watch out for import lockthough. I am guessing this is why Python doesn't solve ctrl-C by default.

不过要注意导入锁。我猜这就是 Python 默认不解决 ctrl-C 的原因。