2011-10-31 33 views
1

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

另外值得注意的是:我有一个SIGINT处理程序,它在调用exit(0)之前执行一些清理操作。如果我使用os.kill(p.pid, signal.SIGTERM)(不是SIGINT)手动终止处理程序中的子进程,那么在通常会发生zombify的情况下,我可以成功地终止子进程。然而,一旦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) 

我通过捕捉所提出的OSERROR固定它我的代码看起来是这样p.wait and exiting:

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

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

回答

2

呼叫p.terminate()在SIGTERM处理程序:

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

[编辑]既然你坚持使用Python 2.5,使用os.kill(p.pid, signal.SIGTERM)代替p.terminate()。检查应确保你没有发现异常(或减少你得到的次数)。

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

+0

这就是我在第一次尝试之前,我意识到p.terminate()是在Python 2.6中添加的,而我被困在2.5。不幸的是,我无法升级Python。 –

+0

我终于设法通过尝试围绕对p.wait()的调用并在发生OSError时发生错误而退出。 –