3

从 Perl 5.10.1 开始,这按预期工作:信号整数被捕获。

#!/usr/bin/perl

use strict;
use warnings;

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

sleep(20);

但是这里 SIGINT 并没有被困住。

#!/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 AD Marshall 1999-2005的脚注

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

有人会解释这个吗?

4

2 回答 2

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 时,会打印

完毕。
END,倒数第二个。睡眠然后打印
^CSIGINT 在 END 块中,得到 zap
醒来。
END,最后运行

所以你需要在代码的最后END添加一个块,.END { $SIG{INT} = 'IGNORE' }

似乎对“END”的更改${^GLOBAL_PHASE}会删除或以其他方式禁用处理程序。

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

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

于 2016-11-19T10:47:41.767 回答
1

perldoc perlmod说:

一个“END”代码块尽可能晚地执行,也就是说, perl 程序运行完成之后,解释器即将退出之前,即使它是作为die()函数的结果而退出的。(但如果它通过“”变成另一个程序exec,或者被信号吹出水面,则不是 - 你必须自己捕获它(如果可以的话)。)

我希望在退出解释器之前删除信号处理程序。因此,我不太能看出什么是令人惊讶或意料之外的。

于 2016-11-19T15:19:22.177 回答