133 votes

Impossible de tuer le script de Python avec Ctrl-C

Je teste le threading de Python 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()

Il fonctionne avec Python 2.7 sur Kubuntu 11.10. Ctrl + C ne le tuera pas. J'ai également essayé d'ajouter un gestionnaire de signaux 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 en arrière plan avec Ctrl + Z ce qui n'est pas ignoré. Pourquoi est-ce que Ctrl + C d'être ignoré de façon si persistante ? Comment puis-je résoudre ce problème ?

0 votes

@dotancohen fonctionne-t-il sous Windows ?

0 votes

@vitaibian : Je n'ai pas testé sous Windows, mais cela semble ne pas être spécifique à l'OS.

212voto

Thomas K Points 16753

Ctrl + C met fin au thread principal, mais comme vos threads ne sont pas en mode démon, ils continuent de tourner, ce qui maintient le processus en vie. On peut en 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 fil principal a lancé vos fils, il n'a plus rien à faire. Il se retire donc, et les threads sont détruits instantanément. Gardons donc le fil principal en vie :

import time
while True:
    time.sleep(1)

Maintenant, il va continuer à imprimer "premier" et "deuxième" jusqu'à ce que vous appuyez sur Ctrl + C .

Edit : comme les commentateurs l'ont souligné, les fils du démon n'ont peut-être pas l'occasion de nettoyer des choses comme les fichiers temporaires. Si vous avez besoin de cela, alors attrapez le KeyboardInterrupt sur le fil principal et lui faire coordonner le nettoyage et l'arrêt. Mais dans de nombreux cas, laisser les threads des démons mourir soudainement est probablement suffisant.

8 votes

Vous devriez mentionner qu'en faisant cela, les threads ne sont pas arrêtés de manière gracieuse et certaines ressources ne sont pas libérées.

3 votes

Eh bien, Ctrl-C n'est jamais une façon élégante d'arrêter quoi que ce soit. Je ne suis pas sûr des ressources qui resteraient - le système d'exploitation ne devrait-il pas récupérer quelque chose lorsque le processus se termine ?

7 votes

@ThomasK Fichiers temporaires créés par tempfile.TemporaryFile() peuvent être laissés sur le disque, par exemple.

8voto

Jon Clements Points 51556

KeyboardInterrupt et les signaux ne sont vus que par le processus (c'est-à-dire le thread principal)... Jetez un coup d'oeil à Ctrl-c c.-à-d. KeyboardInterrupt pour tuer les threads en python

7voto

John Hagelgans Points 31

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 faire en sorte que les boucles se terminent (vous pouvez y ajouter tout ce qui est nécessaire pour le nettoyage). La variable die est vérifiée à chaque passage et lorsqu'elle est vraie, 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 __name__ == '__main__':
    f = MyThread('first')
    f.start()
    s = MyThread('second')
    s.start()
    try:
        while True:
            time.sleep(2)
    except KeyboardInterrupt:
        f.join()
        s.join()

2voto

Hansimov Points 339

Une version améliorée de la réponse de @Thomas K :

  • Définir une fonction d'assistant is_any_thread_alive() en fonction de cette phrase qui peut mettre fin à la main() automatiquement.

Exemples de codes :

import threading

def job1():
    ...

def job2():
    ...

def is_any_thread_alive(threads):
    return True in [t.is_alive() for t in threads]

if __name__ == "__main__":
    ...
    t1 = threading.Thread(target=job1,daemon=True)
    t2 = threading.Thread(target=job2,daemon=True)
    t1.start()
    t2.start()

    while is_any_thread_alive([t1,t2]):
        time.sleep(0)

0voto

Lenz Kappov Points 1

Un simple "gotcha" dont il faut se méfier, êtes-vous sûr que CAPS LOCK n'est pas allumée ?

J'exécutais un script dans l'IDE Thonny sur un Pi4. Avec CAPS LOCK sur, Ctrl + Shift + C est transmis au tampon du clavier, et non Ctrl + C .

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