当父进程死亡时,如何杀死用subprocess.check_output()创建的python子进程?

Cla*_*ara 28 python linux subprocess

我在linux机器上运行一个python脚本,它使用subprocess.check_output()创建一个子进程,如下所示:

subprocess.check_output(["ls", "-l"], stderr=subprocess.STDOUT)
Run Code Online (Sandbox Code Playgroud)

问题是,即使父进程死亡,子进程仍在运行.当父母去世时,我有什么办法可以杀死孩子的过程吗?

mic*_*ses 24

是的,您可以通过两种方法实现这一目标.它们都要求你使用Popen而不是check_output.第一个是更简单的方法,使用try..finally,如下所示:

from contextlib import contextmanager

@contextmanager
def run_and_terminate_process(*args, **kwargs):
try:
    p = subprocess.Popen(*args, **kwargs)
    yield p        
finally:
    p.terminate() # send sigterm, or ...
    p.kill()      # send sigkill

def main():
    with run_and_terminate_process(args) as running_proc:
        # Your code here, such as running_proc.stdout.readline()
Run Code Online (Sandbox Code Playgroud)

这将捕获sigint(键盘中断)和sigterm,但不是sigkill(如果你用-9杀死你的脚本).

另一种方法有点复杂,并使用ctypes的prctl PR_SET_PDEATHSIG.一旦父母出于任何原因退出(即使是sigkill),系统将向孩子发送信号.

import signal
import ctypes
libc = ctypes.CDLL("libc.so.6")
def set_pdeathsig(sig = signal.SIGTERM):
    def callable():
        return libc.prctl(1, sig)
    return callable
p = subprocess.Popen(args, preexec_fn = set_pdeathsig(signal.SIGTERM))
Run Code Online (Sandbox Code Playgroud)

  • 第一种方法刚刚启动并*立即*杀死子进程,您应该在`Popen()`调用后添加`p.communicate()/p.wait()`。[第二种方法仅适用于 Linux](http://www.evans.io/posts/killing-child-processes-on-parent-exit-prctl/) (2认同)

cda*_*rke 21

你的问题是使用subprocess.check_output- 你是对的,你不能使用该接口获得子PID.改用Popen:

proc = subprocess.Popen(["ls", "-l"], stdout=PIPE, stderr=PIPE)

# Here you can get the PID
global child_pid
child_pid = proc.pid

# Now we can wait for the child to complete
(output, error) = proc.communicate()

if error:
    print "error:", error

print "output:", output
Run Code Online (Sandbox Code Playgroud)

要确保在退出时杀死孩子:

import os
import signal
def kill_child():
    if child_pid is None:
        pass
    else:
        os.kill(child_pid, signal.SIGTERM)

import atexit
atexit.register(kill_child)
Run Code Online (Sandbox Code Playgroud)

  • 如果父进程崩溃,则无法保证将调用`atexit`处理程序.顺便说一句,如果你有`proc`对象; 你可以直接调用`proc.kill()`(不需要先提取pid) (2认同)