2017-10-15 8 views
1

J'essaye d'implémenter une icône de plateau, qui me permet de contrôler un processus (jackd). NotammentComment tuer un enfant forké et son sous-processus jackd en python

  • Je veux lire les processus stdout et stderr à des fins d'exploitation forestière
  • Je veux être en mesure de tuer le processus à partir d'une entrée de menu du programme principal

Le meurtre est à l'origine moi des maux de tête. Je crois, quand je lis stdout et stderr je dois le faire dans un thread/processus supplémentaire pour garder l'icône sensible. J'ai donc utilisé fork() pour créer un processus fils et appelé setsid() sur l'enfant. Ce processus enfant invoque alors jackd à l'aide du module subprocess

from subprocess import PIPE, STDOUT, Popen 
def runAndLog(self, cmd): 
    po = Popen(cmd, stdout=PIPE, stderr=STDOUT) 
    line = po.stdout.readline() 
    while line: 
     print(line.rstrip()) 
     line = po.stdout.readline() 
self.runAndLog(["jackd","-R", "-P80", "-t5000", "-dfirewire", "-r44100", "-p256", "-n3"]) 

Maintenant, j'espérais que je pouvais obtenir mon processus fils fourchue et jackd dans le même groupe de processus, pour que je puisse tuer tous les deux en une seule fois, mais à ma grande surprise Popen a créé un nouveau groupe de processus et une nouvelle session:

PID PPID PGID SID COMMAND 
5790 5788 5788 31258 python (parent, main) 
5791 5790 5791 5791 python (forked child after setsid - ok) 
5804 5791 5804 5804 jackd (grandchild created by Popen) 

Alors, tuant l'enfant ne sera pas tuer le petit-enfant et je ne vois aucun moyen propre de faire le PID du petit-enfant (5804) connu main dans afin de le tuer explicitement. Je pourrais probablement utiliser une tromperie de signal pour que l'enfant mourant tue le petit-fils, mais j'hésite à le faire.

Je ne peux pas non plus utiliser setpgid sur le processus jackd pour le forcer dans le groupe de processus de l'enfant, car son SID est différent du SID de mon enfant.

Je crois que je soit

  • dois convaincre Popen de ne pas créer une nouvelle session, ou
  • utiliser un module avec moins de magie que subprocess, mais qui me alows encore à lire stdout et stderr.

mais je ne sais pas comment faire. Certes, mes connaissances sur les groupes de processus sont quelque peu limitées.

/home/martin >python --version 
Python 2.7.1 

Mise à jour le 12 octobre

Je trouve que la nouvelle session n'est pas créée par python mais par jackd lui-même. Quand je remplace jackd avec xterm, tout va bien.

PID PPID PGID SID COMMAND 
12239 4024 12239 4024 python (parent, main) 
12244 12239 12244 12244 python (forked child after setsid - ok) 
12249 12244 12244 12244 xterm (grandchild has same PGID and SID - ok) 

J'ai aussi trouvé this

ces jours Jack appelle setsid() se s'établir en tant que nouveau chef de groupe de processus

Cela ne laisse que les options pour

  • faire connaître le PID de Jack à main et le tuer explicitement ou
  • ont l'enfant en train de mourir tuer tuer jackd

Des conseils à ce sujet?

.

+0

Cette réponse est-elle utile? http://stackoverflow.com/a/4791612 –

+0

C'est à peu près ce que je fais. Cependant, j'ai trouvé que le problème est vraiment jackd lui-même et pas python. Je vais mettre à jour ma question en conséquence. –

+0

Pourquoi n'utilisez-vous pas juste un fil, et contrôlez directement le jack? Pourquoi faites-vous un processus enfant séparé pour contrôler la commande réelle du tout? Quels sont les avantages supposés de le rendre beaucoup plus complexe? –

Répondre

1

Étant donné que votre petit-fils définit ses propres sessions et sid, vous ne pouvez pas vous attendre à ce que le groupe-kill fonctionne correctement. Vous disposez de trois options:

  1. itérer sur l'arbre entier des processus enfants, et tous les tuer à partir des parents (afin qu'ils ne redémarrera pas les enfants). Solution laide et trop compliquée.

  2. Utilisez un fil dans le processus principal (racine) pour contrôler directement l'enfant jack. Le processus enfant intermédiaire n'est probablement pas nécessaire ici, car il ne donne aucun avantage. C'est la solution la plus simple possible.

  3. Si vous avez encore d'avoir le processus enfant intermédiaire, la seule façon est d'attraper les signaux de terminaison envoyés à l'enfant, et de les transmettre au petit-enfant:

child.py:

import signal 
import subprocess 

# The signal handler for the child process, which passes it further to the grandchild. 
def handler(signum, frame): 
    print('Killing self, killing the children') 

    os.kill(proc.pid, signal.SIGTERM) 

    # wait for the process to die gracefully for N secs. 
    time.sleep(5) 

    os.kill(proc.pid, signal.SIGKILL) 

cmd = ["jackd","-R", "-P80", "-t5000", "-dfirewire", "-r44100", "-p256", "-n3"] 
po = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) 

signal.signal(signal.SIGTERM, handler) 

for line in po.stdout: 
    print(line.rstrip()) 

Veuillez noter que le gestionnaire de signaux est installé avant le début de la communication de processus (lecture de ligne). Chaque fois que votre processus racine supprimera "gracieusement" le processus enfant (par exemple, avec SIGTERM), le signal sera transmis au petit-fils, et il sera également arrêté/tué. Vous pouvez même étendre la logique de tuer et d'attendre et de le tuer de force. Cependant, rappelez-vous que si le processus enfant est tué avec SIGKILL, il n'y aura aucune chance d'attraper ce signal, et le petit-enfant restera orphelin. Parce que SIGKILL n'est pas attrapable par conception.