Perl信号处理程序在END块中重置

时间:2016-11-19 01:52:23

标签: perl signals perl5.10

自Perl 5.10.1以来,这可以正常工作:陷入了SIGINT。

#!/usr/bin/perl

use strict;
use warnings;

$SIG{INT} = sub { die "Caught a sigint $!" };

sleep(20);

但是这里的SIGINTs 陷入困境。

#!/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找到解释。我能找到的这种行为的唯一提及是来自Practical Perl Programming A D Marshall 1999-2005

的脚注
  

注意发送到脚本的信号可以绕过END块。

有人会解释这个吗?

2 个答案:

答案 0 :(得分:3)

这对我有用:在首先运行的 END块中重新安装处理程序(代码中的最后一个)。

use warnings;
use strict;
use feature 'say';

$SIG{INT} = sub { say "SIGINT: got zap!" };

#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 "SIGINT in END block, got zap" };
}

几秒钟后启动并按Ctrl-C-ed打印

done.
END, runs next to last. Sleep then print
^CSIGINT in END block, got zap
Woke up.
END, runs last

因此,您需要在代码中添加ENDEND { $SIG{INT} = 'IGNORE' }

似乎更改为" END" ${^GLOBAL_PHASE}删除或以其他方式禁用处理程序。

但是,一旦处理程序在END阶段重新安装,它就会始终有效。当然,在首先执行的END块中这样做是最干净的。

我会更新(如果)我了解更多细节并找到有关此行为的文档。

答案 1 :(得分:1)

perldoc perlmod说:

  

"结束"代码块尽可能晚地执行 ,即 perl之后       已经完成了程序的运行,就在 解释器出现之前       退出 ,即使它因die()函数而退出。 (但不是       它会通过" exec"变成另一个程序,或被吹出       通过信号浇水 - 你必须自己陷阱(如果可以的话)。)

我希望在退出解释器之前删除信号处理程序。因此,我无法看到令人惊讶或意料之外的事情。