Perlでタイムアウト処理を実装する

| | Comments (0) | TrackBacks (0)

プログラムを書く際に処理をタイムアウトさせたい場合というのはよくあると思います。
そんなときに便利なのが、alarmです。
今回は、Perlプログラムでalarmを使ってタイムアウト処理を実装したいと思います。

alarmは対象の処理が指定した時間(秒)たっても終了しない場合、SIGALRMシグナルを発生させます。
例として、ユーザからの入力を30秒でタイムアウトさせるプログラムを書いてみます。

#!/usr/bin/perl

use strict;

# タイムアウトするまでの時間(秒数)
my $TIMEOUT = 30;

print "What your name??: ";
alarm($TIMEOUT);
my $name = ;
my $timeleft = alarm(0);
print "Hello! $name";


alarmで囲った部分、ユーザからの入力待つ部分がタイムアウト処理の対象になります。
ユーザが30秒以上入力しない場合、SIGALRMシグナルが発生しプログラムが終了します。
実際に30秒放置しておくと以下のような画面になります。

[hiroki@capybara]~% ./sig_alarm.pl
What your name??: zsh: alarm      ./sig_alarm.pl
[hiroki@capybara]~%

このままでもプログラムを終了させることはできるのですが、SIGALRM発生後に後処理を行いたいということが多いと思います。
# このプログラムでは特にこのままでも問題ないのですが...
上記のプログラムを改良しタイムアウトした際にメッセージを表示するようにしたいと思います。
evalとdieを組み合わせることで後処理を実装することができます。
下記が実装例です。

#!/usr/bin/perl

use strict;

my $TIMEOUT = 30;

print "What your name??: ";
my $name = '';
eval {
local $SIG{ALRM} = sub {die};
alarm($TIMEOUT);
$name = ;
my $timeleft = alarm(0);
};

if ($@) {
# タイムアウト
print "\nERROR: TIMEOUT\n";
}else{
# 正常終了
print "Hello! $name";
}


まず、タイムアウト処理をしたい対象をevalで囲んでdieしたときでもプログラム自体を終了しないようにします。
dieなどの割り込みが発生した場合には、$@にエラーメッセージが代入されるのでそれによって処理がタイムアウトしたかを判定しています。

eval内では、SIGALRMシグナルが発生したときでもプログラムが終了しないようにSIGALRMのシグナルハンドラを設定しています。
シグナルハンドラには関数のリファレンスを渡す必要があります。
上記例では、SIGALRMが発生した際にはdieするようにしています。
シグナルハンドラはlocalをつけて指定することで、スコープ内で発生した該当のシグナルだけつかまえることができます。
localを指定していない場合、プログラム全体の該当のシグナルハンドルを指定することになります。

上記のプログラムを実際にタイムアウトさせると下記のようになります。

[hiroki@capybara]~% ./sig_alarm.pl
What your name??:
ERROR: TIMEOUT
[hiroki@capybara]~%

今度はシェルからのメッセージではなく、きちんと自分自身のプログラムからのメッセージが表示されているのがわかると思います。


最後にalarmとsleepを併用することは推奨されません。
sleepがalarmを使って実装されていることが多く、正しく動かないことがあるからです。


alarmとevalとdieを組み合わせることでタイムアウトがないような処理にもタイムアウトが実装できるようになります。

0 TrackBacks

Listed below are links to blogs that reference this entry: Perlでタイムアウト処理を実装する.

TrackBack URL for this entry: http://lab.hde.co.jp/blog/mt-tb.cgi/140

Leave a comment

About this Entry

This page contains a single entry by takayasu published on July 23, 2009 2:54 PM.

OpenSSL 1.0.0 Beta3 が出てた was the previous entry in this blog.

日経225のSPF対応状況(2009年7月) is the next entry in this blog.

Find recent content on the main index or look in the archives to find all content.