2010-03-30 9 views
3

utilisant Python 2.6.1 sous Mac OS X 10.6.2, j'ai le problème suivant:pipe.communicate appelant Python() dans un thread

J'ai un processus fileté (une classe de discussion), et chaque de ces fils comporte un tuyau (a subprocess.Popen) quelque chose likeso:

from threading import Thread 

cmd = "some_cmd" 

class Worker(Thread): 
    def run(self): 
     pipe = Popen(cmd, 
     stdin=PIPE, 
     stdout=PIPE, 
     stderr=PIPE) 

     out, err = pipe.communicate("some data") 

le problème est que le code pipe.communicate() est bloquant. Fait intéressant, lorsque j'ai envoyé une interruption (par exemple Ctrl-C KeyboardInterrupt) au processus parent, il se débloque.

Fait intéressant, quand j'utilise class Worker(multiprocessing.Process), le code fonctionne très bien.

Toute idée à savoir pourquoi cela bloque - et comment y remédier - serait grandement appréciée.

Merci.

+0

Juste trouvé http://stackoverflow.com/questions/984941/python-subprocess-popen-from-a-thread - cependant je ne suis pas sûr de ce que le correctif est (encore)! –

+0

Il semblerait que Popen ne soit pas compatible avec les threads. Soyez très obligé pour une correction ou une clarification. Trouvé http://mail.python.org/pipermail/python-bugs-list/2007-August/039177.html sur le sujet. –

+0

communiquent() est supposé bloquer. Voulez-vous dire qu'il bloque tout le programme et pas seulement le fil sur lequel il tourne? Pourriez-vous fournir un exemple de programme complet? –

Répondre

1

Si vous appelez sys.exit() dans le thread principal, les autres threads se terminent à la prochaine opportunité (sur la plupart des systèmes d'exploitation). Cependant, s'ils sont dans un appel bloquant (tel que communiquez()), ils attendent que l'appel de blocage se termine avant de se terminer. Control-C fonctionne parce que le système d'exploitation interrompt l'appel de blocage.

Généralement, l'approche la plus sûre consiste à s'assurer qu'aucun de vos threads n'appelle des fonctions qui peuvent se bloquer indéfiniment. Malheureusement, cela implique souvent d'écrire beaucoup plus de code.

Dans votre cas, vous pouvez stocker les objets Popen dans un set() global avant d'appeler communiquer, et ont le principal appel de fil Popen.terminate() sur chacun d'eux juste avant de quitter. Cela provoquerait la sortie de l'enfant, communicate() pour revenir et le thread pour quitter.

Définissez-vous le fil comme un filetage daemon?

1

L'utilisation de plusieurs threads et entraîne souvent des problèmes, en particulier (mais pas exclusivement) sur les systèmes basés sur Unix; Je vous recommande d'éviter de mélanger les deux.

Questions connexes