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になってほしい。
追記
.@antipop それ Test::SharedFork のアレでできるよ
forkなんだから共有しなくていいんじゃないの。したいときだけtieとかIPC::*なんちゃらとか。
諸氏に教えをいただいた。
上記の$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
追々記
id:nihenさんが共有データのIPCをすることなく、いい感じにcallbackを実行するやりかたを書いてくださいました。
SIGCHLDで実行するのですねー。なるほどなるほどー。勉強になります。