Subscribed unsubscribe Subscribe Subscribe

Kentaro Kuribayashi's blog

Software Engineering, Management, Books, and Daily Journal.

Fork::setTimeout

g:subtech:id:cho45:detailさんが、AnyEventでJavaScriptのsetTimeout()的なものを書いていたので(AnyEvent::setTimeout - 冬通りに消え行く制服ガールは✖夢物語にリアルを求めない。 - subtech)、forkで同じようなことをしてみました。

use Fork::setTimeout;

my $timer = setTimeout(sub {
  warn "1sec!";
}, 1000);

とか書けます。setTimeout()にわたしたcoderefをforkした子プロセスで実行しつつタイマーオブジェクトを返して、そいつがスコープを抜けるタイミングで適当にwaitpidしたりします。

が、以下のようなコードがうまくいかない。どうしたらいいんだろう。

my $i = 0;

setTimeout(sub { $i++ }, 1000);
sleep 3;

warn $i; #=> 0

$iは1になってほしい。

追記


諸氏に教えをいただいた。

上記の$iは、子プロセスにコピーされるので親プロセスから見ると0になっちゃうのは当然。プロセス間でデータを共有したい場合は、たとえばIPC::Shareableを使ってshared memoryなりなんなりを通して共有するとよいようだ。というわけで、以下のように書くと期待通りにはなりました。

use IPC::Shareable;

my $handle = tie my $i, 'IPC::Shareable', undef, { destroy => 1 };
$i = 0;

my $timer5 = setTimeout(
    sub {
        $handle->shlock;
        $i++;
        $handle->shunlock;
    }, 1000
);

sleep 3;

warn $i; #=> 1

参考: Parallel::ForkManager + IPC::Shareable で複数のプロセスで変数を共有する

追々記

id:nihenさんが共有データのIPCをすることなく、いい感じにcallbackを実行するやりかたを書いてくださいました。

SIGCHLDで実行するのですねー。なるほどなるほどー。勉強になります。