如何正确杀死应用程序启动的所有进程?

问题描述:

我们有一个用Python编写的大型应用程序。当我们关闭或中断它时,我们希望干净地杀掉我们的应用程序启动的进程。然而,通过Python代码(例如subprocess.Popen或使用os.system),我们有一个命令这将启动子命令另一个但命令似乎与命令无关。命令B的父进程是init进程(使用pid 1)。如何在Python代码中杀死进程B(例如在Ctrl + C之后)?如何正确杀死应用程序启动的所有进程?

例如,我们有两个shell脚本和一个调用这些shell脚本的Python脚本。

第一外壳脚本mycommand1.sh是:

#!/bin/sh 
sleep 3600 & 

第二壳脚本mycommand2.sh是:

#!/bin/sh 
sleep 3600 

的Python脚本myscript.py是:

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" 

然后我们执行我们的Python脚本,并在3秒后用Ctrl + C打断它。 这是中断后的输出。

$> 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 

我们显示所有的“睡眠”过程,而与Python脚本执行后(当然,还有就是Python脚本执行之前没有睡眠过程)。

当运行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 

用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 

正如我们所看到的,我们试图杀死进程1不存在并且父pid为1的一个进程睡眠总是存在。此进程睡眠来自脚本mycommand1.sh的执行。如何正确杀死这个进程睡眠脚本myscript.py(当然,我们不希望杀死所有的睡眠进程)?

+0

。我做了你所描述的一切 – RedEyed

+0

非常感谢你对我的问题的兴趣。我在Mac(macOS Sierra 10.12.3)上做了这些实验,我的Python版本是2.7.13。我已经复制了我在我的问题中编写的所有代码,我刚才在启动python命令(chmod 755 mycommand * .sh)之前为shell脚本添加了权限,并且我很好地重现了这个问题。 –

+0

我在Ubuntu 17上测试它,并且无法重现它。我也在Python 2.7.13上测试了它。 – RedEyed

尝试重写mycommand1.sh

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

foo & 

mycommand2.sh

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

foo 

myscript.py 删除stdout=subprocess.PIPE进行检查。

我遵循您的所有说明。这里是输出:

$> 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 

在Ctrl + C之后,脚本mycommand1.sh继续运行。

注:1427和1428分别是过程1的我不能重现它的PGID和2

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