61 votes

le threading ignore l'exception KeyboardInterrupt

J'exécute ce code simple :

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

Mais quand je l'exécute, il imprime

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

En fait, le fil de python ignore mon Ctrl + C interruption du clavier et n'imprime pas Received Keyboard Interrupt . Pourquoi ? Quel est le problème de ce code ?

74voto

unutbu Points 222216

Essayez

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

Sans l'appel à time.sleep le processus principal consiste à sortir de l'eau. try...except trop tôt, de sorte que le bloc KeyboardInterrupt n'est pas prise. Ma première idée était d'utiliser thread.join mais cela semble bloquer le processus principal (en ignorant le KeyboardInterrupt) jusqu'à ce que l'option thread est terminé.

thread.daemon=True fait en sorte que le thread se termine lorsque le processus principal se termine.

6 votes

Je crois qu'un délai d'attente sur join c'est-à-dire while thread.isAlive: thread.join(5) fonctionnera également pour que le thread principal reste réactif aux exceptions.

14 votes

thread.daemon = True n'est en fait pas recommandé car il ne permet pas au thread de nettoyer les ressources laissées derrière lui...

13voto

rattray Points 675

Pour résumer les changements recommandés dans le site commentaires le texte suivant fonctionne bien pour moi :

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 votes

Le fait d'appeler "thread.join()" encore et encore dans le "while thread.isAlive() :" est-il une bonne chose / est-ce important ?

0 votes

Personnellement, je ne sais pas ; cela pourrait valoir la peine d'essayer d'élaborer un point de référence si la perf vous importe pour cela ?

1 votes

Soyez conscient que exit() et sys.exit() ne sont pas les mêmes. Il est recommandé d'utiliser sys.exit().

8voto

yaccob Points 688

Légère modification de la solution d'ubuntu.

Suppression de tread.daemon = True comme suggéré par Eric et remplacement de la boucle de sommeil par 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'

0voto

Albert Points 12642

Ma solution (bricolée) est de faire du "monkey-patch". Thread.join() comme ça :

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

0voto

personal_cloud Points 862

Mettre le try ... except dans chaque fil et aussi un signal.pause() en vrai main() fonctionne pour moi.

Faites attention à verrou d'importation cependant. Je suppose que c'est la raison pour laquelle Python ne résout pas le problème de ctrl-C par défaut.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X