Estou estudando o comportamento do kernel Linux há algum tempo e sempre ficou claro para mim que:
Quando um processo morre, todos os seus filhos são devolvidos ao
init
processo (PID 1) até que acabem morrendo.
No entanto, recentemente, alguém com muito mais experiência do que eu no kernel me disse que:
Quando um processo termina, todos os filhos também morrem (a menos que você use o
NOHUP
caso em que eles retornaminit
).
Agora, apesar de não acreditar nisso, ainda escrevi um programa simples para garantir isso. Eu sei que não devo confiar no time ( sleep
) para testes, pois tudo depende do agendamento do processo; no entanto, para este caso simples, acho que isso é suficiente.
int main(void){
printf("Father process spawned (%d).\n", getpid());
sleep(5);
if(fork() == 0){
printf("Child process spawned (%d => %d).\n", getppid(), getpid());
sleep(15);
printf("Child process exiting (%d => %d).\n", getppid(), getpid());
exit(0);
}
sleep(5);
printf(stdout, "Father process exiting (%d).\n", getpid());
return EXIT_SUCCESS;
}
Aqui está a saída do programa, com o ps
resultado associado sempre que se printf
fala:
$ ./test &
Father process spawned (435).
$ ps -ef | grep test
myuser 435 392 tty1 ./test
Child process spawned (435 => 436).
$ ps -ef | grep test
myuser 435 392 tty1 ./test
myuser 436 435 tty1 ./test
Father process exiting (435).
$ ps -ef | grep test
myuser 436 1 tty1 ./test
Child process exiting (436).
Agora, como você pode ver, isso se comporta exatamente como eu esperava. O processo órfão (436) é devolvido a init
(1) até que ele morra.
No entanto, existe algum sistema baseado em UNIX no qual esse comportamento não se aplica por padrão? Existe algum sistema no qual a morte de um processo desencadeie imediatamente a morte de todos os seus filhos?
nohup
comdisown
.disown
é um componente embutido em algum shell que remove um trabalho em execução da tabela de trabalhos (usando um argumento semelhante%1
), e o principal efeito colateral útil disso é que o shell não envia um SIGHUP ao subprocesso.nohup
é um utilitário externo que ignora o SIGHUP (e faz poucas outras coisas) e inicia o comando passado em sua linha de comando.nohup
de fato ignora o sinal antes de serexec
o comando.Isso está correto se o processo for um líder de sessão. Quando um líder da sessão morre, um SIGHUP é enviado a todos os membros dessa sessão. Na prática, isso significa seus filhos e seus descendentes.
Um processo se torna líder de sessão chamando
setsid
. Os reservatórios usam isso.fonte
fork
mate o processo paisetsid
) e forcei outro filho para essa nova sessão. No entanto, quando o processo pai (novo líder da sessão) morreu, a criança não recebeu nenhum SIGHUP e se apegouinit
até que finalmente saísse.setpgid(2)
manual: Se uma sessão tiver um terminal de controle e o sinalizador CLOCAL para esse terminal não estiver definido e ocorrer uma interrupção do terminal, o líder da sessão receberá um SIGHUP. Se o líder da sessão sair, um sinal SIGHUP também será enviado para cada processo no grupo de processos em primeiro plano do terminal de controle.Portanto, o que os pôsteres acima estão dizendo é: as crianças não morrem, os pais as matam (ou enviam um sinal no qual elas terminam). Portanto, você pode ter o que pede, se programar o Pai para (1) manter um registro de todos os filhos e (2) enviar um sinal para todos os filhos.
É isso que o Shell faz e deve ser o que o processo pai faz. Pode ser necessário capturar o sinal HUP no pai, para que você ainda tenha controle suficiente para matar os filhos.
fonte
Estou faltando um pouco nas respostas que estão um pouco relacionadas aos pais que estão morrendo: quando um processo escreve em um canal para o qual não há mais processo de leitura, ele recebe um SIGPIPE. A ação padrão para SIGPIPE é finalização.
Isso pode realmente causar processos para morrer. De fato, é a maneira padrão pela qual o programa
yes
morre.Se eu executar
no meu sistema, a resposta é
e 141 é realmente 128 + SIGPIPE:
de
man 7 signal
.fonte