我有这段代码来超时长时间运行的进程(在这种情况下为sleep
):
#!/usr/bin/env perl
use strict;
use warnings;
die "Usage: $0 SLEEP TIMEOUT\n" unless @ARGV == 2;
my ( $sleep, $timeout ) = @ARGV;
$|++;
eval {
local $SIG{ALRM} = sub { die "TIMEOUT\n" };
alarm $timeout;
eval {
# long-running process
print "Going to sleep ... ";
sleep $sleep;
print "DONE\n";
};
alarm 0; # cancel timeout
};
die $@ if $@;
当我将其作为./alarm 5 2
运行时,我希望die
说“TIMEOUT”。然而它以0退出并且什么也没说。当我删除内部eval
块(不是块的内容,只是eval
)时,它按预期工作。有人可以解释为什么会这样吗?感谢。
答案 0 :(得分:1)
因为您在第一个eval
块中捕获了错误,而第二个eval
块没有异常并清除$@
。
eval {
local $SIG{ALRM} = sub { die "TIMEOUT\n" };
alarm $timeout;
eval {
# long-running process
print "Going to sleep ... ";
A: sleep $sleep;
print "DONE\n";
};
B:
alarm 0; # cancel timeout
C:};
die $@ if $@;
$sleep
> $timeout
,因此在A:
您的计划会抛出SIGALRM
。信号由本地信号处理程序捕获并调用die "TIMEOUT\n"
。因此,Perl将$@
设置为"TIMEOUT\n"
并在B:
处继续执行。然后,您的程序会将其转到C:
,而不会出现任何其他错误。由于您的外部eval
块已正常完成,因此Perl会清除$@
,并且您的最终die
语句不会执行。
要做你想做的事,你可以
eval
die $@ if $@
调用