Подтвердить что ты не робот

Threading игнорирует исключение 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
`

Фактически поток python игнорирует мое прерывание клавиатуры Ctrl + C и не печатает Received Keyboard Interrupt. Зачем? Что не так с этим кодом?

4b9b3361

Ответ 1

Попробуйте

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 заставляет поток прекращаться, когда заканчивается основной процесс.

Ответ 2

Чтобы подвести итоги, рекомендованные в комментариях, для меня хорошо работает следующее:

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

Ответ 3

Небольшая модификация решения ubuntu.

Удаление tread.daemon = Истина, предложенная Эриком, и замена спального цикла на 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'

Ответ 4

Мое решение (hacky) для monkey-patch 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

Ответ 5

Помещение try ... except в каждом потоке, а также signal.pause() в true main() работает для меня.

Следите за блокировкой импорта. Я предполагаю, что Python по умолчанию не разрешает ctrl-C.