1

Je rencontre des problèmes lorsque j'essaie de terminer un processus en cours s'exécutant sur un thread séparé.Comportement incohérent lors de la tentative de fermeture du sous-processus python s'exécutant sur un thread

Ci-dessous est le programme. WorkOne crée un sous-processus et exécute un processus long "adb logcat" qui génère des lignes de journal. Je démarre WorkOne dans main(), attendez 5 secondes et essayez de l'arrêter. pistes multiples donne plusieurs sorties

import threading 
import time 
import subprocess 
import sys 

class WorkOne(threading.Thread): 

    def __init__(self): 
     threading.Thread.__init__(self) 
     self.event = threading.Event() 
     self.process = subprocess.Popen(['adb','logcat'], stdout=subprocess.PIPE, stderr=sys.stdout.fileno())  

    def run(self): 
     for line in iter(self.process.stdout.readline,''):    
      #print line 
      if self.event.is_set(): 
       self.process.terminate() 
       self.process.kill() 
       break; 
     print 'exited For' 

    def stop(self): 
     self.event.set() 

def main(): 

    print 'starting worker1' 
    worker1 = WorkOne() 
    worker1.start() 
    print 'number of threads: ' + str(threading.active_count()) 
    time.sleep(5) 
    worker1.stop() 
    worker1.join(5) 
    print 'number of threads: ' + str(threading.active_count()) 

if __name__ == '__main__': 
    main() 

Parfois, je reçois [A]:

starting worker1 
number of threads: 2 
number of threads: 2 
exited For 

Parfois, je reçois [B]:

starting worker1 
number of threads: 2 
number of threads: 1 
exited For 

Parfois je suis [C]:

starting worker1 
number of threads: 2 
number of threads: 2 

Je pense que je devrais m'attendre à obtenir [B] tout le temps e. Qu'est-ce qui ne va pas ici?

+1

Étant donné que vous définissez un délai d'expiration dans l'appel 'join()', il est possible de conserver le thread actif même s'il a été arrêté (par exemple, il attend une nouvelle ligne dans la boucle 'for'). –

+0

On dirait que c'était le problème, déplacé le terminer et tuer les appels de la boucle for à la méthode d'arrêt et maintenant je reçois la sortie cohérente que je m'attends – Harkish

Répondre

0

Je pense que [B] est seulement possible si le sous-processus prend moins de 10 secondes: Le thread principal dort 5 secondes, et après cela worker finit dans le délai de 5 secondes de join().

Pendant 10 secondes ou plus, worker peut être en vie même après l'appel join() car il a un argument de temporisation, qui peut arriver ou non. Ensuite, vous pouvez obtenir [A] (le sous-processus se termine quelques secondes plus tard) ou [C] (le sous-processus se termine beaucoup plus tard). Pour obtenir toujours [B], supprimez l'argument timeout de join() afin que le thread principal attende jusqu'à ce que worker se termine (ou assurez-vous de supprimer le processus dans les 10 secondes en plaçant l'appel kill en dehors de la boucle).

0

changement

 if self.event.is_set(): 
      self.process.terminate() 
      self.process.kill() 
      break; 

à

 if self.event.is_set(): 
      self.process.terminate() 
      self.process.wait() 
      break 

Le point-virgule est un don mort qu'il ya un problème ici.

Je devine que sans le wait() le fil débloque parfois le work1.join(5) trop tôt. Dans ces cas, threading.active_count() retourne 2.

Et, comme @ A.Rodas dit, work1.join(5) devrait être work1.join() à la jointure assurer ne pas débloquer jusqu'à ce que work1 est fait.


D'ailleurs, je ne sais pas pourquoi vous avez toujours voulu appeler terminate puis kill successivement. Sur Unix, kill est une forme plus grave de terminate. Sur Windows, ils sont identiques. Donc, si vous appelez kill, il n'est pas nécessaire d'appeler terminate.

Puisque vous connaissez le programme appelé par subprocess, vous devez également savoir si l'arrêt suffit pour l'arrêter.

Par conséquent, vous devez en avoir seulement besoin: self.process.terminate() ou self.process.kill().

Questions connexes