読者です 読者をやめる 読者になる 読者になる

forkとexecのお話

Perl Hackers Hub: UNIXプログラミングの勘所を読もうと思ったが、

「複製」と言っても,全部の情報が複製されるわけではありません。プロセスのメモリイメージが複製される(注2)一方で,プロセスが開いている「オープンファイル記述」(open file description)(注3)は複製されません。forkのあとは,親プロセスと子プロセスの両者が,単一のオープンファイル記述を指す「ファイル記述子」(file descriptor)(注4)を持つことになります(図2)

...既によく分からない。基本を押さえねば。


実際にコード書いてみないと、(ボクは)身に付かないので当たり前の確認をいくつかやってみる。

メモリは複製される
my $foo = 'foo';

my $pid = fork;
die $! unless ( defined $pid );

if ( $pid == 0 ) {
    $foo = 'bar';
    sleep 3;
    print "child: $foo\n";
}
else {
    wait;
    print "parent: $foo\n";
}

child: bar
parent: foo

メモリは複製される(=共有ではない)ので、同一変数を子プロセスで変更したとしても親には影響与えない。

execしてもpidは同じ
exec ( 'ps', $$ );

  PID   TT  STAT      TIME COMMAND
  970 s002  R+     0:00.01 ps 970

そもそもexecってそういうものだけど、PID同じだー。

環境変数はexecした時に継承される
$ENV{PAGER} = 'more';
exec qw/printenv PAGER/;

more

これも当たり前かもしれないけど、execから別コマンドを実行する時、環境変数は継承されますねー。

オープンファイル記述は複製されない
aaa
bbb
ccc

「オープンファイル記述」がなんであるかはよくわかってないですが...こんな中身のファイルがあるとして

open( my $fh, '<', 'input.txt') or die $!;

my $pid = fork;
die $! unless ( defined $pid );

my $line;
if ( $pid == 0 ) {
    $line = <$fh>;
    print "child:$line";
  close $fh;
    exit;
}

#wait;
$line = <$fh>;
print "parent:$line";
close $fh;

の結果は、waitの有無で変わっちゃう。そういうことなんですね。


だいぶアタマがすっきりしてきました。
で、fork-execって何のためにあるんだろう?という疑問がアタマをよぎったので調べたところ、pipeと組み合わせるらしい。ということで、次はpipeを調べることにします。あとはfile descriptorもわかんないからこれも。

追記(2012/01/08)

file descriptorはforkで共有されずprocessごとに持つことになるけど、オープンファイル記述(offsetとか)は共有なので子と親のどちらで先に読み出すかで結果が変わるよ、ということでした。