wait関数 - 子プロセスの終了を待つ
forkで分岐させた場合は親プロセスと子プロセスはどちらが先に終了するかはわかりません。今回は親プロセスが子プロセスの終了を待つ方法を解説します。
1. waitで子プロセスの終了を待つ
子プロセスの終了を待つにはwait関数を使用します。wait関数はひとつの子プロセスが終了するまで待機し続けます。戻り値は終了した子プロセスのプロセスIDです。子プロセスが何らかの理由で自動的に回収されていた場合は-1が返却されます。
my $pid = wait;
子プロセスを待つサンプルです。前回のサンプルを少し修正します。結果がわかりやすいように、子プロセス側でprint文を実行する前に、sleep関数で2秒待機しています。
use strict; use warnings; my $pid = fork; die "Cannot fork: $!" unless defined $pid; if ($pid) { # 子プロセスの終了を待機する。 wait; print "親プロセス(子プロセスID: $pid)\n"; } else { # 子プロセスで2秒待つ sleep 2; print "子プロセス\n"; }
出力結果は
子プロセス 親プロセス( 子プロセスID: 25870 )
となります。親プロセスが子プロセスを待機していることがわかると思います。
2. 子プロセスの終了とプロセステーブルからの削除
子プロセスが終了した場合、即座にプロセステーブルから削除されるわけではありません。(プロセステーブルはOSがプロセスを管理するために使用されます。)
子プロセスは終了後にプロセステーブルから削除されるのを待ちます。この状態のことを指して「死んだ子プロセス」と呼ばれます。子プロセスがプロセステーブルからの削除を待つのは親プロセスが子プロセスの終了スターテスを知る必要があるからです。
waitを呼び出すと終了した子プロセスがプロセステーブルから削除されます。また親プロセスが終了した場合も子プロセスはプロセステーブルから削除されます。
3. 子プロセスの終了ステータス
waitを呼ぶと
$?
という特殊変数に子プロセスの終了ステータスを含めた複数のデータが格納されます。$?の中に格納された子プロセスの終了ステータスの取得の仕方については次回解説します。
4. waitが本当に行っていること
実際はwaitは子プロセスの終了を待っているのではありません。子プロセスがCHLDシグナルを発生させるのを待っています。CHLDシグナルは子プロセスの終了時だけではなく、子プロセスが停止した場合や、再開した場合にも発生します。
これはwaitを使用しても確実には死んだ子プロセスを回収できないということを意味します。確実に死んだ子プロセスを回収するには、CHLDシグナルのシグナルハンドラにIGNOREを設定するか、waitpid関数を適切に使用します。