SIGALRM をスケジューリングする
alarm
は、SECONDS に指定した秒数が経過したら自身のプロセスに SIGALRM を発生させます。
これは一種のタイマーとして機能します。
SECONDS が指定されなかったら、$_
が使われます。
タイマーは一つしかセットすることができません。
すでにタイマーが存在するのにも関わらず、再度 alarm
を呼び出すと、
以前のタイマーはキャンセルされ、新たなタイマーがセットされることになります。
以前のタイマーをキャンセルするには、SECONDS に 0 を指定します。
alarm
はよく時間がかかりそうな処理のタイムアウトの実装に使われます。
次のサンプルコードは、時間がかかりそうな処理に対して 5 秒のタイムアウトを設けています。
eval {
# ALRM シグナルをキャッチしたら die して eval を抜ける
local $SIG{ALRM} = sub { die "alarm\n" };
# ALRM シグナルを 5 秒後に発するよう設定
alarm 5;
# 時間がかかりそうな処理を実行
&do_heavy_something();
# ALRM シグナルを解除
alarm 0;
};
if ($@) {
# ALRM シグナルによってタイムアウトを検知した場合
if ( $@ eq "alarm\n" ) {
print "タイムアウトしました。";
}
# &do_heavy_something() で例外が発生した場合
else {
print "処理に失敗しました: $@\n";
}
}
細かい点ですが、die
に指定するメッセージの最後に
"\n"
を加えている点に注意してください。
もし最後に "\n"
を加えないと、
die
はエラーを出力する際に
"alarm at ./sample.pl line 6."
のように、
ファイル名や行番号の情報を付加してしまいます。
$@
の値を評価する際の邪魔になりますので、意図的に
die
に引き渡すメッセージの最後に
"\n"
を加えているのです。
1 秒未満の精度でタイマーを作りたい場合は、
Time::HiRes
モジュールの
ualarm
を使うと良いでしょう。
ualarm
ならマイクロ秒の単位でタイムアウトを指定することができます。
Time::HiRes は Perl 5.8 から標準モジュールになっています。