Perl中捕获和处理信号

信号是操作系统向进程(如Perl程序)发送的消息类型。信号提供了一种与进程通信的方法,例如在运行命令行程序时,按下control-c默认会向程序发送中断信号(‘SIGINT’)来终止它。信号通常是不预期的,如果没有处理,可能会导致您的Perl程序或数据处于未完成的状态。本文介绍了处理信号的一些有用的Perl编程工具。

方法1:%SIG散列

所有Perl程序都有一个全局变量%SIG散列,其中包含与每种信号类型相对应的键。当向Perl程序发送信号时,%SIG中匹配键名的值将自动解引用。这使得可能将代码引用分配给处理特定信号的代码,通过在%SIG中信号键的值中添加一个代码引用来实现。让我们用一个名为sleeper.pl的示例Perl脚本来演示。sleeper.pl所做的只是休眠20秒

use strict;
use warnings;

sleep(20);

现在让我们更新sleeper.pl以使用%SIG处理中断信号

use strict;
use warnings;

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

sleep(20);

如果我们通过命令行运行sleeper.pl并按control-c发送SIGINT给它,我们可以看到我们的代码引用被执行了

perl sleeper.pl
^CCaught a sig int Interrupted system call at projects/scripts/sleeper.pl line 4.

通过更新%SIG中的各种键值对,可以处理特定信号,例如我们可以更新sleeper.pl以处理终止信号

use strict;
use warnings;

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

sleep(20);

通常,定义信号处理子程序比为要捕获的每个信号使用匿名子程序更容易。让我们相应地更新sleeper.pl

use strict;
use warnings;

$SIG{INT}  = \&signal_handler;
$SIG{TERM} = \&signal_handler;

sleep(20);

sub signal_handler {
    die "Caught a signal $!";
}

现在,每当sleeper.pl收到SIGINT或SIGTERM信号时,signal_handler子程序将被调用。使用这些技术,可以扩展您希望处理的信号的所有信号的处理行为。

方法2:sigtrap

sigtrap是一个有用的Perl祈使句,使处理信号比直接操作%SIG更容易。sigtrap祈使句识别三组信号:正常信号(HUP、PIPE、INT、TERM)、错误信号(ABRT、BUS、EMT、FPE、ILL、QUIT、SEGV、SYS和TRAP)以及旧接口信号(ABRT、BUS、EMT、FPE、ILL、PIPE、QUIT、SEGV、SYS、TERM和TRAP)。使用sigtrap,我们可以更新sleeper.pl,以便在收到任何正常信号时退出

use strict;
use warnings;
use sigtrap qw/die normal-signals/;

sleep(20);

我们可以在调用die之前,让sigtrap调用我们之前定义的signal_handler例程

use strict;
use warnings;
use sigtrap qw/handler signal_handler normal-signals/;

sleep(20);

sub signal_handler {
    die "Caught a signal $!";
}

关于sigtrap还有很多内容,请查看sigtrap perldoc条目以获取更多关于其功能的信息。

有用的信号处理行为

在处理SIGINT和SIGTERM时,通常调用die。die很有用,因为它将确保Perl正确停止:例如,在调用die时,Perl将执行析构方法(如果存在),但如果收到SIGINT或SIGTERM且没有信号处理程序调用die,则不会调用析构方法。在信号处理子程序中,有用的其他行为包括堆栈跟踪、事件记录、线程终止和临时文件清理。要定义的正确行为将取决于接收到的信号类型和Perl程序类型。

POSIX信号

并非每个信号都可以处理:在POSIX兼容系统(如BSD、Linux和OSX)上,SIGSTOP和SIGKILL不能捕获、阻塞或忽略。有关详细信息,请参阅signal手册页。并非每个信号都需要处理——每个信号都有一个默认的程序行为(处置),这可能不会影响程序的运行(也在手册页中定义)。您可以在命令行中打印%SIG来找到Perl识别的信号列表

perl -e 'foreach (keys %SIG) { print "$_\n" }'

Windows信号

Windows 实现了标准 POSIX 信号的一部分。这些信号仍然可以使用上述技术进行处理。微软在此处提供了一份这些信号的列表。


本文最初发布在 PerlTricks.com 上。

标签

David Farrell

David是一位专业程序员,他经常在推特博客上分享关于代码和编程艺术的内容。

浏览他们的文章

反馈

这篇文章有什么问题吗?请通过在GitHub上打开问题或拉取请求来帮助我们。