Od dłuższego czasu badam zachowanie jądra Linuksa i zawsze było dla mnie jasne, że:
Kiedy proces umiera, wszystkie jego dzieci są zwracane do
init
procesu (PID 1), aż w końcu umrą.
Jednak ostatnio ktoś z dużo większym doświadczeniem z jądrem powiedział mi, że:
Kiedy proces się kończy, wszystkie jego dzieci również umierają (chyba że użyjesz,
NOHUP
w którym przypadku wrócąinit
).
Teraz, chociaż w to nie wierzę, wciąż napisałem prosty program, aby się tego upewnić. Wiem, że nie powinienem polegać na czasie ( sleep
) na testach, ponieważ wszystko zależy od planowania procesu, ale w tym prostym przypadku myślę, że to wystarczy.
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;
}
Oto wynik programu, z powiązanym ps
wynikiem za każdym razem, gdy printf
mówi:
$ ./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).
Teraz, jak widać, zachowuje się tak, jak bym się spodziewał. Proces osierocony (436) jest zwracany do init
(1) aż do śmierci.
Czy jednak istnieje system oparty na systemie UNIX, w którym takie zachowanie nie jest domyślnie stosowane? Czy istnieje system, w którym śmierć procesu natychmiast powoduje śmierć wszystkich jego dzieci?
nohup
siędisown
.disown
jest wbudowany w jakąś powłokę, która usuwa działające zadanie z tabeli zadań (biorąc pod uwagę argument podobny%1
), a głównym użytecznym efektem ubocznym jest to, że powłoka nie wysyła ZATRZYMANIA do podprocesu.nohup
to zewnętrzne narzędzie, które ignoruje SIGHUP (i robi kilka innych rzeczy), a następnie uruchamia polecenie przekazane w wierszu polecenia.nohup
w rzeczywistości ignoruje sygnał przed wydaniemexec
polecenia.Jest to prawidłowe, jeśli proces jest liderem sesji. Kiedy lider sesji umiera, SIGHUP jest wysyłany do wszystkich członków tej sesji. W praktyce oznacza to jego dzieci i ich potomków.
Proces staje się liderem sesji przez wywołanie
setsid
. Muszle tego używają.źródło
fork
zabij proces nadrzędnysetsid
) i rozwidliłem kolejne dziecko do tej nowej sesji. Jednak gdy proces nadrzędny (nowy lider sesji) zmarł, dziecko nie otrzymało SIGHUP i przywiązało sięinit
do niego, aż w końcu zakończyło pracę.setpgid(2)
strony podręcznika: Jeśli sesja ma kontrolujący terminal, a flaga CLOCAL dla tego terminala nie jest ustawiona, a wystąpi rozłączenie terminala, lider sesji jest wysyłany SIGHUP. Jeśli lider sesji wyjdzie, wówczas sygnał SIGHUP zostanie również wysłany do każdego procesu w grupie procesów pierwszego planu terminala sterującego.Tak więc powyższe plakaty mówią, że dzieci nie umierają, rodzic je zabija (lub wysyła im sygnał, na którym kończą). Możesz więc mieć to, o co prosisz, jeśli zaprogramujesz Rodzica, aby (1) prowadził rejestr wszystkich swoich dzieci i (2) wysyłał sygnał do wszystkich swoich dzieci.
To właśnie robi Shell i powinno to być to, co robi proces nadrzędny. Konieczne może być złapanie sygnału HUP u rodzica, aby nadal mieć wystarczającą kontrolę, aby zabić dzieci.
źródło
Brakuje mi trochę odpowiedzi, która jest nieco związana z umierającymi rodzicami: kiedy proces pisze na rurze, dla której nie ma już procesu czytania, otrzymuje SIGPIPE. Standardowe działanie dla SIGPIPE to wypowiedzenie.
To może rzeczywiście spowodować śmierć procesów. W rzeczywistości jest to standardowy sposób, w jaki program
yes
umiera.Jeśli wykonam
w moim systemie odpowiedź brzmi:
a 141 to w rzeczywistości 128 + SIGPIPE:
z
man 7 signal
.źródło