gpt4 book ai didi

linux - perl 信号处理只在 sighandler 调用子程序时工作一次

转载 作者:太空狗 更新时间:2023-10-29 11:42:47 27 4
gpt4 key购买 nike

设置:内核:4.1.16-v7+操作系统:armv7l GNU/Linux(主要是 debian)

This is perl 5, version 20, subversion 2 (v5.20.2) built for arm-linux-gnueabihf-thread-multi-64int

较大的 perl 代码有一部分外部进程有时在一定的时间限制内没有响应。发生此错误时,“main”子例程将通过 signal_handler 命令“restartservice”重新启动

在调试这个问题的过程中,我发现了许多关于信号处理的描述,尤其是在你使用信号处理程序后重新初始化它。

http://www.perlmonks.org/?node_id=440900

报价:

Not all platforms automatically reinstall their (native) signal handlers >after a signal delivery. This means that the handler works only the first >time the signal is sent. The solution to this problem is to use "POSIX" >signal handlers if available, their behaviour is well-defined.

所以我试图弄清楚 POSIX 的实现方式,直到我从 http://perldoc.perl.org/perlipc.html 中复制示例后才找到解决方案并使用我的“restartservice”子例程对其进行了增强。

我的问题似乎是:当执行 signal_handler 时,我无法调用已定义的子例程。

例子:

#!/usr/bin/perl
use warnings;
use strict;

sub restartservice()
{
print "alarm reached\n";
main();
};

sub main()
{
while (1){
print "while loop\n";
eval {
#local $SIG{ALRM} = sub { print "alarm main\n"; main();" };#fails
local $SIG{ALRM} = sub { print "alarm main\n"; next; };#works
#local $SIG{ALRM} = \&restartservice; #does not work ,proove below
alarm 2;
sleep 5;# here i would use my normal code which sometimes hangs
alarm 0;

};
};
}
main();

输出工作情况证明:

perl perlalarm.pl 
while loop
alarm main
Exiting subroutine via next at perlalarm.pl line 17.
Exiting eval via next at perlalarm.pl line 17.
while loop
alarm main
Exiting subroutine via next at perlalarm.pl line 17.
Exiting eval via next at perlalarm.pl line 17.
while loop
alarm main
...

不工作情况的输出证明:

perl perlalarm.pl 
while loop
alarm reached
while loop
while loop
while loop

我想知道我必须做什么才能让子例程在该信号处理程序中工作。

最佳答案

通常,当您在信号处理程序中时,信号会被屏蔽,除非您通过 sigaction 设置 SA_NODEFER 标志。调用(在 perl 中:POSIX::SigAction)。

因此,您从信号处理程序中第二次调用 main() 运行 main() 并阻止 SIGALRM。你的执行看起来像这样:

time | No Signals Blocked | SIGALRM Blocked
-----+--------------------+------------------
0 | main() |
1 | while ... |
2 | eval { |
3 | $SIG{ALRM}... |
... | sleep |
| <<ALARM>> | $SIG{ALRM} invoked
n | | restartservice()
n+1 | | main()
n+2 | | while ...
n+3 | | ....
n+4 | | <<ALARM>> # <-- blocked, no effect

好的做法是在信号处理程序中做一些非常小和离散的事情,比如设置标志,或者有时抛出异常。在 perl 中,eval{}+alarm 习惯用法通常是后者:

while (1) {
my $ok = eval {
local $SIG{ALRM} = sub { die "ALARM"; };
alarm(5);
do_something();
alarm(0);
1; # $ok
};
next if $ok;
if ($@ =~ /ALARM/) {
# timed out
} else {
# some other failure
}
}

关于linux - perl 信号处理只在 sighandler 调用子程序时工作一次,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36067317/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com