perl信号处理只有在sighandler调用子程序时才起作用

设置:内核:4.1.16-v7 +操作系统:armv7l GNU / Linux(主要是debian)

This is perl 5, version 20, subversion 2 (v5.20.2) built for arm-linux-gnueabihf-thread-multi-64int 

一个较大的Perl代码有一部分外部进程,有时在一定的时间限制内没有响应。 发生此错误时,通过signal_handler命令“restartservice”重新启动“main”子例程

在debugging这个问题时,我发现了很多有关信号处理的描述,尤其是在你使用信号处理器后重新初始化信号处理器。

和http://www.perlmonks.org/?node_id=440900

qouting:

在信号传递之后,并非所有的平台都会自动重新安装它们的(本地)信号处理程序。 这意味着处理程序只能处理信号发送的第一个时间。 解决这个问题的办法是使用“POSIX”>信号处理程序(如果有的话),它们的行为是明确的。

所以我试图找出POSIX的方式,没有find解决scheme,直到我从http://perldoc.perl.org/perlipc.html复制的例子,并增强了我的“restartservice”子程序。

我的问题似乎是:当signal_handler被执行时,我不能调用已经定义的子程序。

例:

 #!/usr/bin/perl use warnings; use strict; sub restartservice() { print "alarm reached\n"; main(); }; sub main() { while (1){ print "while loop\n"; eval { #local $SIG{ALRM} = sub { print "alarm main\n"; main();" };#fails local $SIG{ALRM} = sub { print "alarm main\n"; next; };#works #local $SIG{ALRM} = \&restartservice; #does not work ,proove below alarm 2; sleep 5;# here i would use my normal code which sometimes hangs alarm 0; }; }; } main(); 

产出情况:

 perl perlalarm.pl while loop alarm main Exiting subroutine via next at perlalarm.pl line 17. Exiting eval via next at perlalarm.pl line 17. while loop alarm main Exiting subroutine via next at perlalarm.pl line 17. Exiting eval via next at perlalarm.pl line 17. while loop alarm main ... 

不工作情况的输出certificate:

 perl perlalarm.pl while loop alarm reached while loop while loop while loop 

我想知道我得做些什么才能得到一个在该信号处理程序中工作的子程序。

一般来说,当你在一个信号处理程序中时,信号被屏蔽,除非你通过一个sigaction调用来设置SA_NODEFER标志(在perl:POSIX :: SigAction中)。

所以,你在信号处理程序中第二次调用main() ,SIGALRM会阻塞main() 。 你的执行看起来像这样:

 time | No Signals Blocked | SIGALRM Blocked -----+--------------------+------------------ 0 | main() | 1 | while ... | 2 | eval { | 3 | $SIG{ALRM}... | ... | sleep | | <<ALARM>> | $SIG{ALRM} invoked n | | restartservice() n+1 | | main() n+2 | | while ... n+3 | | .... n+4 | | <<ALARM>> # <-- blocked, no effect 

好的做法是在信号处理程序中做非常小​​而离散的事情,比如设置一个标志,或者有时会抛出一个异常。 在perl中, eval{}+alarm成语通常是后者:

 while (1) { my $ok = eval { local $SIG{ALRM} = sub { die "ALARM"; }; alarm(5); do_something(); alarm(0); 1; # $ok }; next if $ok; if ($@ =~ /ALARM/) { # timed out } else { # some other failure } } 

一旦你在指定的子程序中将main()替换成next main()以使其等同于匿名程序,它也开始工作。