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

问题描述 投票:0回答:2

自 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 块。

有人能解释一下吗?

perl signals perl5.10
2个回答
3
投票

这对我有用:在 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
 块中执行此操作是最干净的。


1
投票

perldoc perlmod 说:

“END”代码块会尽可能晚地执行

,即afterperl 已完成运行程序,就在解释器正在运行之前 exited

,即使它是由于 
die() 函数而退出。 (但不是如果 它通过“exec”变形为另一个程序,或者被吹出 通过信号来浇水——你必须自己捕获它(如果可以的话)。)

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

© www.soinside.com 2019 - 2024. All rights reserved.