簡體   English   中英

當sighandler調用子例程時,perl信號處理僅工作一次

[英]perl signal processing only works once when sighandler calls subroutine

設置:內核: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代碼具有外部過程的一部分,該過程有時在一定的時間限制內沒有響應。 發生此錯誤時,可通過signal_handler命令“ restartservice”重新啟動“ main”子例程。

在調試此問題期間,我發現了許多有關信號處理的描述,尤其是在使用后重新初始化信號處理程序。

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

qouting:

並非所有平台>在信號傳送后都會自動重新安裝其(本機)信號處理程序。 這意味着處理程序僅在第一次發送信號時起作用。 解決此問題的方法是使用“ POSIX”>信號處理程序(如果可用),它們的行為是明確定義的。

因此,我試圖弄清楚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

我想知道要在該信號處理程序中運行子例程該怎么辦。

一旦在命名子例程中將main()替換為next main()使其等效於匿名子例程),它也將開始工作。

一般來說,當你是一個訊號處理器中的信號被屏蔽,除非你設置SA_NODEFER通過標志sigaction調用(在Perl:POSIX ::的sigaction)。

因此,您從信號處理程序中對main()第二次調用在阻止SIGALRM的情況下運行main() 您的執行如下所示:

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
  }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM