Python 2.5中可靠终止子进程
我有一个脚本,它会反复运行一个Ant构建文件,并把输出抓取成可以解析的格式。当我用Popen创建子进程时,有一个小的时间窗口,在这个窗口内按Ctrl+C会终止脚本,但不会终止正在运行Ant的子进程,这样就会留下一个“僵尸”进程,它会继续在控制台输出内容,只有通过任务管理器才能杀掉它。一旦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 个回答
在你的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
(不带参数)重新抛出这个异常。