Почему дочерний процесс, убитый из-за ошибки сегментации, не умирает сразу?

Мне нужно написать код 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, а на экран выводится сообщение «Произошла ошибка сегментации».
То же самое происходит, если я пытаюсь смоделировать исключение с плавающей запятой из-за деления на ноль.< br> Почему это происходит?


person Shashank Shet    schedule 25.12.2016    source источник
comment
Программирование жестоко. (Знаете, детей убивают и тому подобное.)   -  person anonymous    schedule 13.02.2018


Ответы (1)


Из документации

Popen.wait() Дождитесь завершения дочернего процесса. Установить и вернуть атрибут кода возврата.

Таким образом, returncode не устанавливается до тех пор, пока не будет вызван wait.

В качестве альтернативы вы можете выполнить неблокирующую проверку, чтобы увидеть, завершен ли процесс, используя poll, что также установит returncode в случае завершения.

Popen.poll() Проверить, завершился ли дочерний процесс. Установить и вернуть атрибут кода возврата.

обратите внимание, что вам действительно не нужен вызов 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++.

person Jean-François Fabre    schedule 25.12.2016