IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Python Discussion :

Tuer un thread


Sujet :

Python

  1. #1
    Membre averti
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    51
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 51
    Par défaut Tuer un thread
    Salut,

    Petite difficulté technique. J'ai créé un programme ou l'utilisateur passe des paramètres avec des boutons puis une simulation en thread s'exécute en parallèle. Le problème qui se produit est que j'ai créé un bouton pour arrêter la simulation. J'ai définit une variable Terminated initialisée à 0. La simulation s'exécute tant que que Terminated = 0. Si l'utilisateur clique sur 'Arrêter la simulation', Terminated passe à 1, et là je sors de ma boucle de calcul. Jusque là pas de problème.

    Mais là où ça devient plus compliqué, c'est si je redémarre la simulation, il me dit que mon thread est déjà 'start'. Logique, avec ma méthode, mon thread n'est jamais réellement considéré comme terminé. Quelqu'un connaitrait il une méthode propre et simple pour tuer un thread?

  2. #2
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour,

    Il n'y a pas d'instruction prévue pour "tuer" un thread, mais il existe des astuces.

    Celles que j'utilise sont ici:

    http://python.jpvweb.com/mesrecettespython/arret_thread

    Tyrtamos

  3. #3
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    Bonsoir,

    Je ne comprends pas cette solution tyrtamos. La méthode run des thread permet de lancer la fonction passer en argument target dans le __init__ du Thread.

    Du coup, je ne vois pas comment ta méthode peut fonctionner avec un Thread classique

    Exemple pour illustrer mon propos:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    import threading, time
     
    def compteur(end):
        i = 0
        while i < end:
            i += 1
            print i
            time.sleep(1)
     
    t = threading.Thread(target=compteur,args=(10,))
    t.start()
    t.join()
    raw_input("Fin !")
    ici t.start() invoque implicitement t.run() qui se charge à son tour d'invoquer compteur(). La fonction compteur étant bloquante, une boucle infinie dans le run pour capturer un appel de stopthread est sans effet non ?

    ou alors j'ai pas compris ce que tu fais

  4. #4
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Bonjour kango,

    Je programme toujours mes thread sous forme de classe, parce que je trouve ça plus clair.

    Mais ton exemple a 2 problèmes:

    - le t.join() dit au programme principal: "attend que le thread s'arrête". Et effectivement, il attend...

    - le "end" passé en paramètre de la fonction thread ne peut pas être changé par le programme principal pendant que le thread s'exécute.

    Voilà un code qui résout ces 2 points:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    import threading, time
     
    def compteur():
        global end
        i = 0
        while i < end:
            i += 1
            print i
            time.sleep(1)
     
    end = 10
    t = threading.Thread(target=compteur)
    t.start()
    time.sleep(5)
    end = 0
    raw_input("Fin !")
    Ce qui affiche:

    1
    2
    3
    4
    5
    6
    Fin !
    Cependant, ça ne marche qu'en console, et pas sous idle, écrit lui-même en python.

    Ok?

    Tyrtamos

  5. #5
    Membre averti
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    51
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 51
    Par défaut Pas fastoche
    J'avoue que j'ai un peu de mal à comprendre mais je vais analyser ça en détail à tête reposée

  6. #6
    Membre éclairé
    Avatar de airod
    Homme Profil pro
    Gérant Associé, DMP Santé et Directeur technique
    Inscrit en
    Août 2004
    Messages
    767
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 49
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : Gérant Associé, DMP Santé et Directeur technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Août 2004
    Messages : 767
    Par défaut
    as tu lu la faq?
    http://python.developpez.com/faq/?page=Thread

    perso avant de lancer la simulation je ferais un MonThread._Thread__stop()
    pour etre sur que celui ci est détruit.

  7. #7
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    oui oui je comprends bien tyrtamos

    le t.join() rend l'exécution bloquante, en fait ma question c'est plutôt comment tu implémenterais l'exemple que je donne avec ta méthode, sachant que la fonction compteur doit rester tel quelle.

    Je ne vois pas comment tu peux écrire la méthode run en fait et sans utiliser la variable globale pour le end bien entendu car toute fonction ne se limite pas à une boucle while

  8. #8
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    @ kango:

    J'ai repris ton 1er message, et: désolé, mais je n'ai pas bien compris ce que tu me demandes.

    Ton 1er code fonctionne: tel que programmé, le thread s'arrête tout seul après avoir compté i jusqu'à end.

    C'est seulement si tu veut l'arrêter avant que i arrive à end que le problème se pose, car il faut alors que le programme principal puisse changer la valeur d'une variable utilisée par le thread comme test de boucle while.

    Voilà dans ce cas comment on pourrait coder cela avec une classe:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    import threading, time
     
    class Compteur(threading.Thread):
     
        def __init__(self, end):
            threading.Thread.__init__(self)
            self.end = end
     
        def run(self):
            i = 0
            while i < self.end:
                i += 1
                print i
                time.sleep(1)
     
        def stop(self):
            self.end = 0
     
    t = Compteur(10)
    t.start()
    time.sleep(5)
    t.stop()
     
    raw_input("Fin !")
    Dans cet exemple, le thread devrait durer 10 secondes, mais le programme principal l'arrête au bout de 5 secondes.

    Tu vois qu'on peut se passer de variable globale, grâce au fait que l'attribut de classe self.end est initialisé et est donc dispo dans toutes les méthodes de la classe.

    Quand on lance l'exécution de la méthode t.stop(), elle change self.end, ce qui arrête la boucle while du run et donc arrête le thread.

    Une fois qu'on a compris comment coder les thread sous forme de classe, on considère que c'est la méthode "normale" tellement elle est pratique et puissante.

    Tyrtamos

  9. #9
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    oki, je comprends cette implémentation. mais c'est un cas très particulier ici car la méthode run contient un while.

    Imaginons que la fonction que nous voulons mettre dans un thread est une lourde opération de calcul (matriciel par exemple) ou alors une opération de copie d'arborescence avec shutil.copytree()

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    def CopieRepertoire(threading.Thread):
     
        def __init__(self,src,dest):
            threading.Thread.__init__(self)
            self.src = src
            self.dest = dest
     
        def run(self):
            shutil.copytree(self.src,self.dest)
    Comment faire ici ? Ce que je veux mettre en évidence c'est que tu peux effectivement arrêter un Thread à condition d'avoir sous-classer la classe Thread mais que ceci ne fonctionne que si la fonction à threader est spécifiquement conçue pour être arrêtée. Ce qui peut ne pas être le cas.

    Du coup, il ne me semble pas qu'il y ait de solution universelle permettant de stopper les threading.Thread, quelqu'ils soient.

    Le problème est différent pour les subprocess.Popen et eux pour le coup sont arrêtables

    Voir aussi le module multiprocessing qui implémente des processus "lourds" du genre subprocess.Popen avec l'interface des threading.Thread.

    Pour le problème que rencontre nicogigo, il semble qu'il ait un mécanisme comme celui que tu implémentes tyrtamos. Le problème est qu'un Thread ne peut pas être "start" plusieurs fois.

    Du coup peut être que la solution est de recréer un nouveau Thread avec les mêmes paramètres et appeler la méthode start sur ce Thread là

    En tout cas c'est ce que j'ai fait récemment, le fait de cliquer sur le bouton instancie le thread et lance le start dans la foulée. De ce fait je peux "relancer" le thread.

  10. #10
    Expert confirmé
    Avatar de tyrtamos
    Homme Profil pro
    Retraité
    Inscrit en
    Décembre 2007
    Messages
    4 486
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Var (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Retraité

    Informations forums :
    Inscription : Décembre 2007
    Messages : 4 486
    Billets dans le blog
    6
    Par défaut
    Citation Envoyé par kango Voir le message
    Du coup, il ne me semble pas qu'il y ait de solution universelle permettant de stopper les threading.Thread, quelqu'ils soient.
    Effectivement, tuer un thread n'est pas prévu. Et je n'ai jamais réussi avec la méthode citée dans la FAQ ('_Thread__stop()'), méthode qui n'est pas citée dans la doc.

    Par contre, j'avais à résoudre le problème que tu cites. Dans une calculatrice (ma Calculext), j'avais un eval que je n'arrivais pas à arrêter. J'y ai réussi en utilisant sys.settrace: voir l'adresse que j'ai donnée plus haut. Le principe est de pouvoir tester un drapeau d'arrêt entre chaque ligne de code python. Il suffit alors de générer une exception dans le run pour arrêter le thread. En fait, sys.settrace est prévu pour le debugging, mais c'est tout ce que j'ai trouvé.

    Sinon, il n'est pas obligatoire d'arrêter un thread pour lui faire changer de travail! Un thread peut être codé pour fonctionner en permanence, mais il faut qu'il puisse savoir quand il doit arrêter le travail précédent et lancer le travail suivant.

    Dernier point, pour qu'un thread s'arrête en même temps qu'on arrête le programme principal, il faut le déclarer comme 'daemon'.

    Tyrtamos

  11. #11
    Membre émérite
    Homme Profil pro
    Inscrit en
    Décembre 2007
    Messages
    758
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 46
    Localisation : France

    Informations professionnelles :
    Secteur : Aéronautique - Marine - Espace - Armement

    Informations forums :
    Inscription : Décembre 2007
    Messages : 758
    Par défaut
    Citation Envoyé par tyrtamos Voir le message
    J'y ai réussi en utilisant sys.settrace
    oui très intéressant comme approche, faut que je teste

Discussions similaires

  1. Tuer un thread bloqué en lecture.
    Par Anonymouse dans le forum Concurrence et multi-thread
    Réponses: 8
    Dernier message: 08/02/2008, 11h36
  2. tuer un thread en attente (socket)
    Par LesLemmings dans le forum Visual C++
    Réponses: 1
    Dernier message: 18/03/2007, 09h50
  3. Probléme pour tuer un Thread
    Par peyo_le_fou dans le forum POSIX
    Réponses: 5
    Dernier message: 04/11/2006, 14h10
  4. [D6] Comment tuer un Thread ?
    Par Lung dans le forum Langage
    Réponses: 6
    Dernier message: 28/04/2006, 11h42
  5. [Debutant] Faut-il tuer les Threads Static?
    Par sniperseb dans le forum MFC
    Réponses: 5
    Dernier message: 05/12/2005, 14h43

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo