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

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

Берегисьблокировка импорта хоть. Я предполагаю, что именно поэтому Python не решает Ctrl-C по умолчанию.

Решение Вопроса

Пытаться

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

 Jan-Philip Gehrcke11 сент. 2012 г., 21:51
Я считаю тайм-аут наjoinт.е.while thread.isAlive: thread.join(5) также будет работать, чтобы основной поток реагировал на исключения.
 Erik Allik29 сент. 2013 г., 16:47
thread.daemon = True на самом деле не рекомендуется, потому что это не позволяет потоку очистить любые оставленные ресурсы ...

Мое (хакерское) решение - это обезьяна-патч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

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

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()
 rattray19 нояб. 2016 г., 00:07
Спасибо @DevPlayer! Обновлено, чтобы отразить это. Для любопытных смотритеstackoverflow.com/a/19747562/1048433 для объяснения
 rattray16 сент. 2016 г., 02:43
Лично я не знаю; Возможно, стоит попытаться создать эталон, если для вас это важно?
 DevPlayer15 сент. 2016 г., 15:39
Является ли вызов thread.join () снова и снова в "while thread.isAlive ():" хорошей вещью / имеет ли это значение?
 DevPlayer18 нояб. 2016 г., 02:23
Имейте в виду, что exit () и sys.exit () не совпадают. Рекомендуется использовать sys.exit ().

Удаление 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'
 Tobias Kienzler25 авг. 2016 г., 11:36
Хорошо - но, к сожалению, не поддерживается в Windows

Ваш ответ на вопрос