可靠地终止Python 2.5上的子进程

时间:2011-10-31 14:12:35

标签: python subprocess

我有一个脚本,它反复运行Ant构建文件并将输出转换为可解析的格式。当我使用Popen创建子进程时,有一个小时间窗口,按Ctrl + C将终止脚本,但不会杀死运行Ant的子进程,留下一个打印输出到控制台的僵尸,只能使用Task杀死经理。一旦Ant开始打印输出,按Ctrl + C将始终杀死我的脚本以及Ant。有没有办法让它按下Ctrl + C总是会杀死运行Ant的子进程,而不会留下一个僵尸?

另外值得注意的是:我有一个SIGINT处理程序,它在调用exit(0)之前执行一些清理操作。如果我使用os.kill(p.pid, signal.SIGTERM)(而不是SIGINT)手动终止处理程序中的子进程,那么我可以在通常僵尸化的情况下成功终止子进程。但是,一旦Ant开始生成输出,当你按Ctrl + C时,你会从子进程获得一个堆栈跟踪,它无法杀死子进程本身,因为我已经杀了它。


编辑:我的代码看起来像:

p = Popen('ls')
def handle_sig_int(signum, stack_frame):
    # perform cleanup
    os.kill(p.pid, signal.SIGTERM)
    exit(0)
signal.signal(signal.SIGINT, handle_sig_int)

p.wait()

错误触发时会产生以下堆栈跟踪:

File "****.py", line ***, in run_test
  p.wait()
File "/usr/lib/python2.5/subprocess.py", line 1122, in wait
  pid, sts = os.waitpid(self.pid, 0)
File "****.py", line ***, in handle_sig_int
  os.kill(p.pid, signal.SIGTERM)

我通过捕获p.wait引发的OSError并退出:

来修复它
try:
    p.wait()
except OSError:
    exit('The operation was interrupted by the user')

这似乎适用于我的绝大多数测试运行。我偶尔会得到一个uname: write error: Broken pipe,虽然我不知道是什么原因造成的。如果我在子进程开始显示输出之前恰好在Ctrl + C之前计时,似乎就会发生这种情况。

1 个答案:

答案 0 :(得分:2)

在SIGTERM处理程序中调用p.terminate()

 if p.poll() is None: # Child still around?
     p.terminate() # kill it

[编辑] 由于您坚持使用Python 2.5,因此请使用os.kill(p.pid, signal.SIGTERM)代替p.terminate()。检查应确保您没有得到例外(或减少获得例外的次数)。

为了使它更好,您可以捕获异常并检查消息。如果它表示“未找到子进程”,则忽略该异常。否则,请使用raise(无参数)重新抛出它。