为什么由于分段错误导致子进程不能立即死亡?

问题描述:

我需要编写一个接受某个输入并打印相应输出的C++代码。此代码旨在使用Python子流程模块运行。无论输入和输出如何,我都需要确保Python代码不会由于C++代码遇到运行时错误而提前终止。 C++代码的基本性质是:如下为什么由于分段错误导致子进程不能立即死亡?

int main() 
{ 
    /*The pointer is initialized to NULL to simulate a segmentation fault 
    Also the n is meant for simulating input.*/ 
    int *p=NULL,n; 
    cin>>n; 
    cout<<*p<<endl; //This causes a segmentation fault. 
} 

其运行它的Python代码,如下:

from subprocess import * 
from signal import * 

def handler(signum,frame): 
    raise RuntimeError("Runtime Error") 

call(["g++","try.cpp"]) 
a = Popen(["stdbuf","-i0","-o0","-e0","./a.out"],stdin = PIPE,stdout = PIPE) 
try: 
    #Handler for signal due to termination of child process 
    signal(SIGCHLD,handler)  
    a.stdin.write("1\n") 
    temp = a.stdout.readline() 
except RuntimeError as e: 
    print e 
    print a.returncode 

#Returncode of process killed due to SIGSEGV is -11 
    if a.returncode == -11: 
     print "Segmentation Fault Occurred" 

这就是问题。即使C++代码遇到分段错误,信号处理程序也会被调用,但引发RuntimeError,但Popen对象的返回码为none,表示该进程仍然存在。
现在,如果下面的变化到由除块:

a.wait() 
print a.returncode   
if a.returncode == -11: 
    print "Segmentation Fault Occurred" 

问题已解决。输出显示Popen对象的返回码是-11,并且“屏幕出现分段错误”被打印到屏幕上。
如果我尝试模拟由于被零除的浮点异常,情况完全相同。
这是为什么发生?

+0

编程是残酷的。 (你知道,孩子们被杀死了。) – keeganjk

从文档

Popen.wait() 等待子进程终止。设置并返回returncode属性。

因此returncode没有设置,直到wait被调用。

或者,您可以执行非阻塞检查,以查看是否使用poll终止进程,如果终止,它也会设置returncode

Popen.poll() 检查子进程是否已终止。设置并返回returncode属性。

请注意,您并不需要调用signal(不确定它是否在Windows上可移植)。该代码可以简化这样的:

a = Popen(["stdbuf","-i0","-o0","-e0","./a.out"],stdin = PIPE,stdout = PIPE) 
a.stdin.write("1\n") 
a.stdin.flush() 
temp = a.stdout.readline() 
if temp: 
    # do something 
    print("output "+temp) 
else: 
    # empty string: recieved process has ended, probably unexpectedly 
    # because it should have printed something 
    pass 

returncode = a.wait() 

#Returncode of process killed due to SIGSEGV is -11 
if returncode == -11: 
    print("Segmentation Fault Occurred") 

注意,你必须a.stdin.flush(),以确保输入达到C++程序。