私はしばらくの間Linuxカーネルの振る舞いを研究してきました、そして常に明確でした。
プロセスが終了すると、すべての子プロセスは
init
最終的に終了するまでそのプロセス(PID 1)に返されます。
ところで、最近私よりカーネル経験の多い誰かが私にこう言った。
プロセスが終了すると、その子プロセスもすべて終了します(実行ファイルを使用してを
NOHUP
返さない限りinit
)。
私はこれを信じていませんが、それを確実にするために簡単なプログラムを書いています。私はsleep
テストのために時間()が完全にプロセススケジューリングに依存しているので依存してはいけませんが、この単純なケースではそれだけで十分だと思います。
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;
}
ps
以下は、各printf
会話の関連結果を含むプログラムの出力です。
$ ./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).
今見ているように、これが私が期待したものです。孤児プロセス(436)はinit
終了するまで(1)に返されます。
しかし、この動作をデフォルトで適用しないUNIXベースのシステムはありますか?プロセスが終了するとすぐにすべての子プロセスが終了するシステムはありますか?
答え1
プロセスが終了すると、すべての子プロセスも終了します(NOHUPを使用してinitに戻らない限り)。
これは間違っています。本当に間違っています。そう言う人は、間違っているか、特定の状況を一般的な状況と混同することです。
プロセスが死ぬ方法は2つあります。間接的にその結果、彼の子供たちは死にました。ターミナルが閉じたときに何が起こるかに関連しています。 SIGHUP信号は、端末が消えたときに発生します。 (歴史的には、モデムの切断によってシリアル回線が切断されたため、現在は通常、ユーザーが端末エミュレータウィンドウを閉じているためです。)送信された到着制御プロセスこの端末で実行 - 通常、初期シェルはこの端末で開始されます。シェルは通常終了してそれに反応します。対話型使用のためのシェルは、シャットダウン前に開始する各ジョブにHUPを送信します。
シェルでジョブを開始すると、ジョブはシグナルをnohup
無視し、端末が消えたときに終了するように求められないため、HUPシグナルの2番目のソースが破壊されます。シェルからジョブへのHUP信号の伝播を中断する別の方法は、disown
可能であればシェルの組み込み機能を使用することです(タスクはシェルのジョブリストから削除されます)。が含まれます。独自に子プロセスを開始し、すぐに終了します。シェルは孫プロセスについて知らない。
同様に、ターミナルで開始されたタスクは、親プロセス(シェル)が終了するため終了するのではなく、そのタスクを終了するように指示されたときに、その親プロセスがそのタスクを終了することを決定するために終了します。ターミナルの初期シェルは、親プロセスが死ぬからではなく、ターミナルが消えるために死にます(ターミナルはシェル親プロセスのターミナルエミュレータによって提供されるため、これは偶然かもしれません)。
答え2
プロセスが終了すると、すべての子プロセスも終了します(NOHUPを使用してinitに戻らない限り)。
プロセスがセッションリーダーの場合、これは正しいです。セッションリーダーが死亡すると、SIGHUP はセッションのすべてのメンバーに送信されます。実際、これは子供とその子孫を意味します。
プロセスはを呼び出して自分自身をセッションリーダーにしますsetsid
。これをシェルに使用してください。
答え3
答えで見逃した死んでいる両親と少し関係があります。プロセスが読み取りプロセスを持たないパイプに書き込むと、SIGPIPEを受け取ります。 SIGPIPEの標準操作は終了です。
これにより、実際にプロセスが終了します。実際、これはyes
プログラムを終了する標準的な方法です。
実行すると
(yes;echo $? >&2)|head -10
私のシステムでは、答えは次のとおりです。
y
y
y
y
y
y
y
y
y
y
141
141は実際には128+SIGPIPEです。
SIGPIPE 13 Term Broken pipe: write to pipe with no
readers
からman 7 signal
。
答え4
したがって、上記のポスターが言うのは、子供が死ぬのではなく、両親がそれらを殺すこと(または彼らに終了信号を送ること)ということです。したがって、親が(1)すべての子の記録を維持し、(2)すべての子にシグナルを送信するようにプログラムすることで、必要なものを取得できます。
これがシェルが行うことであり、親プロセスがすべきことです。子供を殺すのに十分なコントロールを持つには、親からHUP信号をキャプチャする必要があります。