在不中断当前睡眠的情况下处理信号

Chr*_*yle 3 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";
Run Code Online (Sandbox Code Playgroud)

无论我设定多sleep长时间,一旦发出QUIT信号sleep结束并且程序继续.

有没有一种方法可以处理QUIT而不影响程序的当前运行,sleep只要它的意图持续下去?

zdi*_*dim 5

在宝贵的睡眠周围设置一个块,忽略其中的信号

IGNORE_QUIT: {
    local $SIG{QUIT} = 'IGNORE';
    sleep 10;
};
Run Code Online (Sandbox Code Playgroud)

如果sleep恰好已经适当地限定了范围,那么您不需要额外的块.

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

sub sleep_protected {
    local $SIG{QUIT} = 'IGNORE';
    sleep $_[0];
}
Run Code Online (Sandbox Code Playgroud)

当地是至关重要的,这样$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;
}
Run Code Online (Sandbox Code Playgroud)

计数器是本地的并返回,但您可以使用全局计数器,声明为our.或者将它声明为一个state变量,它会被记住(见功能).

EINTR如果被信号中断,则中断的调用将返回错误.这可以使用%进行检查!,作为if ($!{EINTR}) {...}.但是,我不知道sleep除了信号之外如何合理地中断,因此没有使用它.