2017-09-12 5 views
2

Nous avons une grande application écrite en Python. Nous souhaitons nettoyer proprement les processus qui ont été lancés par notre application lorsque nous l'avons fermé ou interrompu. Cependant, par le biais du code Python (par exemple subprocess.Popen ou os.system), nous avons une commande A qui lance une autre sous-commande B mais la commande B semble avoir aucune relation avec la commande A. Le processus père de la commande B est le processus init (avec pid 1). Comment tuer le processus B en code Python (par exemple après Ctrl + C)? Par exemple, nous avons 2 scripts shell et un script Python qui appelle ces scripts shell.Comment tuer correctement tous les processus lancés par l'application?

le premier script Shell mycommand1.sh est:

#!/bin/sh 
sleep 3600 & 

le second script Shell mycommand2.sh est:

#!/bin/sh 
sleep 3600 

le script python myscript.py est:

import os 
import signal 
import subprocess 

def launchCommands(): 

    proc1 = subprocess.Popen('./mycommand1.sh', stdout=subprocess.PIPE, shell = True, preexec_fn=os.setsid) 
    print "the processus 1 has started" 

    proc2 = subprocess.Popen('./mycommand2.sh', stdout=subprocess.PIPE, shell = True, preexec_fn=os.setsid) 
    print "the processus 2 has started" 

    return proc1, proc2 


if __name__ == '__main__': 
    proc1 = None 
    proc2 = None 
    try: 
     proc1, proc2 = launchCommands() 
     while True: 
      pass 

    except KeyboardInterrupt: 
     print "Ctrl+C received! ..." 

     print "trying to kill the processus 2" 
     os.killpg(os.getpgid(proc2.pid), signal.SIGTERM) 
     print "processus 2 has been killed" 

     print "trying to kill the processus 1" 
     os.killpg(os.getpgid(proc1.pid), signal.SIGTERM) 
     print "processus 1 has been killed" 

Ensuite, nous exécutons notre script Python et nous l'interrompons après 3 secondes avec un Ctrl + C. Voici la sortie après l'interruption.

$> python myscript.py 
the processus 1 has started 
the processus 2 has started 
^CCtrl+C received! ... 
trying to kill the processus 2 
processus 2 has been killed 
trying to kill the processus 1 
Traceback (most recent call last): 
File "myscript.py", line 33, in <module> 
    os.killpg(os.getpgid(proc1.pid), signal.SIGTERM) 
OSError: [Errno 3] No such process 

Nous proposons tous les processus de « sommeil » pendant et après l'exécution du script Python (Bien sûr, il n'y a pas de processus de sommeil avant l'exécution du script Python).

Pendant l'exécution de la commande myscript.py:

$> ps -ef | grep sleep 
    501 50700  1 0 2:21 ??   0:00.00 sleep 3600 
    501 50701 50699 0 2:21 ??   0:00.00 sleep 3600 
    501 50703 410 0 2:21 ttys002 0:00.00 grep sleep 

Après avoir interrompu le programme avec les touches Ctrl + C:

$> ps -ef | grep sleep 
    501 50700  1 0 2:21 ??   0:00.00 sleep 3600 
    501 51025 410 0 2:23 ttys002 0:00.00 grep sleep 

Comme on le voit, le processus 1, nous essayons de tuer n'existe pas plus et un processus de sommeil dont le père pid est 1 existe toujours. Ce processus de sommeil provient de l'exécution du script mycommand1.sh. Comment tuer correctement ce processus de sommeil dans le script myscript.py (bien sûr, nous ne voulons pas tuer tout le processus de sommeil)?

+0

Je ne peux pas le reproduire. J'ai fait tout ce que vous avez décrit – RedEyed

+0

Merci beaucoup pour votre intérêt pour mon problème. J'ai fait ces expériences sur Mac (macOS Sierra 10.12.3) et ma version de Python est 2.7.13. J'ai copié tous les codes que j'ai écrits dans ma question, je viens d'ajouter des droits pour les scripts shell avant de lancer la commande python (chmod 755 mycommand * .sh) et j'ai bien reproduit le problème. –

+0

Je l'ai testé sur Ubuntu 17, et je ne peux pas le reproduire. Je l'ai également testé sur Python 2.7.13. – RedEyed

Répondre

0

Essayez de réécrire mycommand1.sh

#!/bin/sh 
foo(){ 
    cnt=0 
    while [ $cnt -le 100 ]; do 
     cnt=$((cnt+1)) 
     echo $0 $cnt 
     sleep 1 
    done 
} 

foo & 

et mycommand2.sh

#!/bin/sh 
foo(){ 
    cnt=0 
    while [ $cnt -le 100 ]; do 
     cnt=$((cnt+1)) 
     echo $0 $cnt 
     sleep 1 
    done 
} 

foo 

Retirez stdout=subprocess.PIPE de myscript.py et le vérifier.

0

Je suis toutes vos instructions. Voici la sortie:

$> python myscript.py 
    1427 
    the processus 1 has started 
    1428 
    the processus 2 has started 
    ./mycommand1.sh 1 
    ./mycommand2.sh 1 
    ./mycommand1.sh 2 
    ./mycommand2.sh 2 
    ^CCtrl+C received! ... 
    trying to kill the processus 2 
    processus 2 has been killed 
    trying to kill the processus 1 
    Traceback (most recent call last): 
    File "myscript.py", line 38, in <module> 
     os.killpg(os.getpgid(proc1.pid), signal.SIGTERM) 
    OSError: [Errno 3] No such process 
$> ./mycommand1.sh 3 
    ./mycommand1.sh 4 
    ./mycommand1.sh 5 
    ./mycommand1.sh 6 
    ./mycommand1.sh 7 
    ./mycommand1.sh 8 
    ./mycommand1.sh 9 

Après Ctrl + C, le script mycommand1.sh continue de s'exécuter.

Note: 1427 et 1428 sont respectivement pgid des processus 1 et 2.

proc1or2 = subprocess.Popen('./mycommand1or2.sh', shell = True, preexec_fn=os.setsid) 
print(os.getpgid(proc1or2.pid)) 
print "the processus 1or2 has started"