日記はScrapboxに移動しました。

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で実行するのですねー。なるほどなるほどー。勉強になります。

Leave a Reply

Your email address will not be published. Required fields are marked *