web-dev-qa-db-fra.com

Impossible de tuer Python avec Ctrl-C

Je teste Python threading avec le script suivant:

import threading

class FirstThread (threading.Thread):
        def run (self):
                while True:
                        print 'first'

class SecondThread (threading.Thread):
        def run (self):
                while True:
                        print 'second'

FirstThread().start()
SecondThread().start()

Cela tourne dans Python 2.7 sur Kubuntu 11.10. Ctrl+C ne va pas le tuer. J'ai également essayé d'ajouter un gestionnaire pour les signaux du système, mais cela n'a pas aidé:

import signal 
import sys
def signal_handler(signal, frame):
        sys.exit(0)
signal.signal(signal.SIGINT, signal_handler)

Pour tuer le processus, je le tue par PID après avoir envoyé le programme à l’arrière-plan avec Ctrl+Z, qui n'est pas ignoré. Pourquoi est-ce Ctrl+C être ignoré de manière persistante? Comment puis-je résoudre ça?

108
dotancohen

Ctrl+C termine le thread principal, mais comme vos threads ne sont pas en mode démon, ils continuent à fonctionner, ce qui maintient le processus actif. Nous pouvons leur faire des démons:

f = FirstThread()
f.daemon = True
f.start()
s = SecondThread()
s.daemon = True
s.start()

Mais il y a un autre problème: une fois que le thread principal a démarré vos threads, il ne reste plus rien à faire. Donc, ça sort, et les fils sont détruits instantanément. Alors gardons le fil conducteur en vie:

import time
while True:
    time.sleep(1)

Maintenant, il restera imprimé en premier et en second jusqu'à ce que vous appuyiez sur Ctrl+C.

Edit: Comme l'ont souligné les commentateurs, les threads de démon peuvent ne pas avoir l'occasion de nettoyer des éléments tels que des fichiers temporaires. Si vous en avez besoin, récupérez le KeyboardInterrupt sur le thread principal et coordonnez le nettoyage et l'arrêt. Mais dans de nombreux cas, laisser les threads démon mourir soudainement est probablement suffisant.

169
Thomas K

KeyboardInterrupt et les signaux ne sont vus que par le processus (le thread principal) ... Regardez Ctrl-c i.e. KeyboardInterrupt pour tuer les threads en python

8
Jon Clements

Je pense qu'il est préférable d'appeler join () sur vos threads lorsque vous vous attendez à ce qu'ils meurent. J'ai pris un peu de liberté avec votre code pour terminer les boucles (vous pouvez également ajouter tout ce dont vous avez besoin de nettoyage). La variable die est vérifiée pour la vérité à chaque passage et lorsqu'il est Vrai, le programme se termine.

import threading
import time

class MyThread (threading.Thread):
    die = False
    def __init__(self, name):
        threading.Thread.__init__(self)
        self.name = name

    def run (self):
        while not self.die:
            time.sleep(1)
            print (self.name)

    def join(self):
        self.die = True
        super().join()

if __== '__main__':
    f = MyThread('first')
    f.start()
    s = MyThread('second')
    s.start()
    try:
        while True:
            time.sleep(2)
    except KeyboardInterrupt:
        f.join()
        s.join()
2
Johan Snowgoose