自 Perl 5.10.1 起,这按预期工作:SIGINT 被捕获。
#!/usr/bin/perl
use strict;
use warnings;
$SIG{INT} = sub { die "Caught a sigint $!" };
sleep(20);
但是这里的信号信号没有被困住。
#!/usr/bin/perl
use strict;
use warnings;
$SIG{INT} = sub { die "Caught a sigint $!" };
END {
sleep(20);
}
可以通过在
END
块中再次设置处理程序来修复此问题,如下所示:
END {
$SIG{INT} = sub { die "Caught a sigint $!" };
sleep(20);
}
但是如果你有多个块,这将不起作用:必须为每个块重新设置处理程序。
我试图解决这个问题,但在 perldoc 找不到解释。我能找到的唯一提及此行为的脚注来自实用 Perl 编程 A D Marshall 1999-2005
注意发送到脚本的信号可以绕过 END 块。
有人能解释一下吗?
这对我有用:在 END 块中重新安装处理程序 首先运行(代码中最后运行)
use warnings;
use strict;
use feature 'say';
$SIG{INT} = sub { say "Got $_[0]" };
#sleep 10;
say "done";
END { say "END, runs last" }
END {
say "END, runs next to last. Sleep then print";
sleep 10;
say "Woke up.";
}
# Executed first in END phase. The sole purpose: to reinstall the handler
END {
$SIG{INT} = sub { say "In END block, got $_[0]" };
}
启动并按 Ctrl-C-ed 几秒钟后将打印此内容
完成。 END,倒数第二个运行。睡觉然后打印 ^C在END块中,得到INT 醒了。 END,最后运行
所以你需要添加一个
END
块,代码中的最后一个,END { $SIG{INT} = 'IGNORE' }
。
对
END
${^GLOBAL_PHASE} 的更改是在运行时(RUN
阶段)完成后进行的,显然删除/禁用了信号处理程序。我在文档中找不到这个。但是,一旦在
END
阶段重新安装处理程序,它就会始终有效。当然,在首先执行的
END
块中执行此操作是最干净的。
perldoc perlmod 说:
“END”代码块会尽可能晚地执行,即after
perl
已完成运行程序,就在解释器正在运行之前 exited,即使它是由于die()
函数而退出。 (但不是如果 它通过“exec
”变形为另一个程序,或者被吹出 通过信号来浇水——你必须自己捕获它(如果可以的话)。)我希望信号处理程序在解释器退出之前被删除。因此,我不太能看出什么是令人惊讶或意料之外的。