处理信号而不会中断当前睡眠

时间:2018-06-22 13:01:49

标签: perl

在下面的代码中,如果在进入休眠状态时出现QUIT信号,则休眠将立即结束,并执行最后一行代码。

#!/opt/tertio/localperl/bin/perl

use strict;
use warnings;

my $quit = 0;

$SIG{'QUIT'} = sub { 
    print "Please dont try to take thread dump as i am not java\n"; 
    $quit++; 
};

my $sleep = shift || 30;
print "I am going to sleep\n";
sleep($sleep);

print "I woke up so will exit, but someone tried to quit me $quit times\n";

无论我将sleep设置了多长时间,一旦我发送QUIT信号sleep,程序就会结束。

是否有一种方法可以处理QUIT而又不影响程序的当前运行,从而使sleep持续到预期的时间?

1 个答案:

答案 0 :(得分:5)

围绕那个宝贵的睡眠建立一个障碍,以忽略其中的信号

IGNORE_QUIT: {
    local $SIG{QUIT} = 'IGNORE';
    sleep 10;
};

如果sleep恰好已经确定了范围,那么您就不需要多余的块了。

如果还有更多的话可以使用包装器

sub sleep_protected {
    local $SIG{QUIT} = 'IGNORE';
    sleep $_[0];
}

local非常重要,因此$SIG{QUIT}不会全局更改,而只能在块内更改。

如果需要信号处理程序(不能仅使用'IGNORE'),则sleep确实会被中断,以便处理程序可以运行。所以您需要重新启动通话

sub sleep_protected {
    my $sl = $_[0];
    my $sigquit;
    local $SIG{QUIT} = sub { 
        say "Got $_[0], but don't do thread dump"; 
        ++$sigquit; 
    };
    $sl -= sleep $sl  while $sl > 0;
    return $sigquit;
}

该计数器是本地计数器,但已返回,但您可以使用全局计数器(由our声明)。或将其声明为state变量,并在每次调用时记住该变量(请参见feature)。

如果被信号中断,则中断的呼叫返回错误EINTR。可以使用%!作为if ($!{EINTR}) {...}进行检查。但是,我不知道sleep怎么可以被信号以外的方式合理地打断,所以没有使用它。