fork/wait/exec
"Operating System Concepts"でこのあたり読んでたので、perlであれこれやってみる。
超基本
子プロセスをwaitし、exit statusを表示するという単純なことをやってみる。
my $pid = fork; die $! unless defined $pid; if ( $pid == 0 ) { sleep 1; exit 1; } print "wait for child($pid)\n"; wait; printf "child exits(%d)\n", $? >> 8;
ちゃんと子プロセスの結果を待って、
wait for child(13465) child exits(1)
という結果が出た。
$SIG{CHILD}
$SIG{CHILD}='IGNORE'に設定すると、親側でwaitしてなくてもzombieプロセスをつくらずに済む。IGNOREにセットしているとwaitは"-1"を返す。
On most Unix platforms, the "CHLD" (sometimes also known as "CLD") sig-
nal has special behavior with respect to a value of 'IGNORE'. Setting
$SIG{CHLD} to 'IGNORE' on such a platform has the effect of not creat-
ing zombie processes when the parent process fails to "wait()" on its
child processes (i.e. child processes are automatically reaped). Call-
ing "wait()" with $SIG{CHLD} set to 'IGNORE' usually returns "-1" on
such platforms.
$SIG{CHLD} = 'IGNORE'; my $pid = fork; die $! unless defined $pid; if ( $pid == 0 ) { sleep 1; exit 1; } print wait; # 実際-1がprintされる
複数のプロセスをfork
試しにこんな感じでやってみる。
use Time::HiRes qw(sleep); main(); sub main { my @children; for ( 1..10 ) { my $pid = fork; child_proc() if ( $pid == 0 ); push @children, $pid; sleep 0.1; } my $finished = wait; print "$finished\n"; print "not wait for all children\n"; } sub child_proc { sleep 1; exec('ls'); }
waitのpodには"returns the pid of the deceased process"と書いてあるので、やはり1つの子プロセスしか回収してくれない模様。当たり前っちゃ当たり前か。
全部のプロセスを待つように変えてみる。
use Time::HiRes qw(sleep); main(); sub main { my %children; for ( 1..10 ) { my $pid = fork; child_proc() if ( $pid == 0 ); $children{$pid} = 1; sleep 0.1; } while ( keys %children ) { my $fin = wait; delete $children{$fin}; printf "pid(%d) end. left: %d\n", $fin, scalar keys %children; } print "all children finished\n"; } sub child_proc { sleep 1; exec('ls /tmp/kotaro'); }
ito.kotaro@mac:~/Dev/Perl/work> perl fork.pl foo pid(14101) end. left: 9 foo pid(14102) end. left: 8 foo pid(14103) end. left: 7 foo pid(14104) end. left: 6 foo pid(14105) end. left: 5 foo pid(14106) end. left: 4 foo pid(14107) end. left: 3 foo pid(14108) end. left: 2 foo pid(14109) end. left: 1 foo pid(14110) end. left: 0 all children finished
まとめ
fork, wait, execがちょっとわかった