我有一个脚本,它反复运行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之前计时,似乎就会发生这种情况。
答案 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
(无参数)重新抛出它。