Linuxでプロセスが死んだらどうなるか?

2010年2月14日

LinuxでWebサーバなどを立ててCGI運用している場合、 よくCGIから子プロセスを生成してCGI外プログラムを実行することは良くあると思います。 そんなとき留意しないと行けないことがあります。
  1. Apacheでは、ある一定回数CGIが応答するとpreforkしていたプロセスが終了するように できている。
  2. Linuxでは、親プロセスが終了すると子プロセスはinitプロセスにつながれる。
1.はApacheの設定で変更できることではありますが、デフォルトで数千回実行するとpreforkにて起動していた CGIプロセスが再起動されるようにできています。従って、CGIから非同期実行で子プロセスを実行し何か処理を バックグラウンドで実行することを期待するようなプログラムは完全とは言えません。 そのようなCGIの場合、親プロセスが死んでしまったら当該子プロセスがどのような振る舞いをするかを十分に 理解しておく必要があります。

2.に書いているとおり、親プロセスが終了したとき子プロセスは終了しません。
Linuxの最も上位プロセスであるinitプロセスにつなぎなおされるのです。 つまり、initプロセスの子プロセスになっているということです。

Linuxでは、exitシステムコールが発行されただけではプロセスは終了しません。 親プロセスがwaitシステムコールで待って、当該システムコールが子プロセスの資源を完全に終了させる ことによって初めて正常終了できるのです。

そうでない場合、子プロセスはゾンビプロセス(topでと表示されます。)となります。 この場合、プロセスディスクリプタなどのプロセス管理資源は残ったままの状態となります。


この状況を回復するためには(ゾンビプロセスを回収するためには)、誰かがwaitシステムコールで 子プロセスの資源を収集する必要があります。従って、親プロセスが終了して、上記2.により initプロセスの子プロセスになって、initが当該子プロセスの資源を回収して初めてゾンビプロセスの 回収が行われるのです。

このようにCGIプログラミングにおいて、プロセスはいつでもApacheにより終了させられるます。 また、一旦親プロセスが終了するとCGI経由の子プロセスはinitの子プロセスとなるため、 再びCGIプロセスから当該子プロセスをwaitで待つことはできなくなり、回収できなくなります。


従って、CGIプロセスから非同期プロセスをどうしても実行したい場合はatやbatchコマンド経由で 最初からApache配下のプロセスとしてではなく、initプロセスの子プロセスとして起動すべきです。 そうすれば、誰かから不特定のタイミングで終了されることはなくなるのでより実装がシンプルになります。