Question

J'ai lu quelque part que exception KeyboardInterrupt ne se pose dans le thread principal en Python. Je lis aussi que le thread principal est bloqué alors que les exécute de fil de l'enfant. Alors, est-ce que cela signifie que CTRL + C ne peut jamais atteindre au fil de l'enfant. J'ai essayé le code suivant:

def main():
    try:
        thread = threading.Thread(target=f)
        thread.start()  # thread is totally blocking (e.g., while True)
        thread.join()
    except KeyboardInterrupt:
        print "Ctrl+C pressed..."
        sys.exit(1)

def f():
    while True:
        pass  # do the actual work

Dans ce cas, il n'y a pas d'effet de CTRL + C sur l'exécution. Il est comme il ne peut pas écouter le signal. Est-ce que je comprends ce dans le mauvais sens? Est-il un autre moyen de tuer le fil en utilisant CTRL + C ?

Était-ce utile?

La solution

Le problème est que vous utilisez thread1.join(), ce qui fera de votre programme d'attendre jusqu'à ce que fin du thread pour continuer.

Les signaux seront toujours pris par le processus principal, car il est celui qui reçoit les signaux, il est le processus qui a threads.

Faire comme vous montrer, vous exécutez une application essentiellement « normale », sans caractéristiques de fil, que vous commencez à 1 fil et attendez jusqu'à ce qu'il se termine pour continuer.

Autres conseils

Si vous voulez avoir thread principal pour recevoir le CTRL + C signal tout en se joindre, il peut être fait en ajoutant délai d'appel join().

Ce qui suit semble fonctionner (ne pas oublier d'ajouter daemon=True si vous voulez mettre fin principale en fait):

thread1.start()
while True:
    thread1.join(600)
    if not thread1.isAlive():
        break

En Python, il est vrai que les exceptions de KeyboardInterrupt sont élevés que dans le thread principal de chaque processus. Mais comme d'autres réponses mentionnées à titre, il est vrai aussi que la méthode bloque Thread.join le thread appelant, dont KeyboardInterrupt exceptions . Voilà pourquoi Ctrl + C semble avoir aucun effet:. L'exécution dans les principaux restes de fil bloqués à la ligne thread.join()

Ainsi, une solution simple à votre question est d'abord, ajouter un argument timeout pour thread.join() et mettre cet appel dans une boucle qui se termine lorsque les sorties de fil de l'enfant, de sorte que les exceptions de KeyboardInterrupt peuvent être soulevées après chaque délai d'attente, et d'autre part, faire le fil de l'enfant daemonic , ce qui signifie que son parent (le fil conducteur ici) va le tuer quand il sort (uniquement fils non démon ne sont pas tués, mais rejoint lorsque leurs sorties mères):

def main():
    try:
        thread = threading.Thread(target=f, daemon=True)  # create a daemon child thread
        thread.start()

        while thread.is_alive():
            thread.join(1)  # join shortly to not block KeyboardInterrupt exceptions
    except KeyboardInterrupt:
        print "Ctrl+C pressed..."
        sys.exit(1)

def f():
    while True:
        pass  # do the actual work

Mais une meilleure solution, si vous contrôlez le code du thread enfant, est d'informer le fil de l'enfant à la sortie gracieusement (au lieu de brusquement comme avec la première solution), par exemple avec un threading.Event:

def main():
    try:
        event = threading.Event()
        thread = threading.Thread(target=f, args=(event,))
        thread.start()
        event.wait()  # wait forever but without blocking KeyboardInterrupt exceptions
    except KeyboardInterrupt:
        print "Ctrl+C pressed..."
        event.set()  # inform the child thread that it should exit
        sys.exit(1)

def f(event):
    while not event.is_set():
        pass  # do the actual work
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top