2012-04-18 36 views
3

从我如何指定Perl系统调用的超时限制?为什么在报警信号处理程序中不死不死呢?

eval { 
    local $SIG{ALRM} = sub { die "alarm\n" }; # NB: \n required 
    alarm $timeout; 
    $nread = sysread SOCKET, $buffer, $size; 
    alarm 0; 
}; 
if ([email protected]) { 
    die unless [email protected] eq "alarm\n"; # propagate unexpected errors 
    # timed out 
} 
else { 
    # didn't 
} 

如果发生超时,应该sub { die "alarm\n" };导致进程结束。我想我无法理解diehttp://www.cs.cf.ac.uk/Dave/PERL/node111.html表示“die()函数用于退出脚本并显示消息供用户阅读”。但是,对于上面的脚本,脚本将在#timed输出中处理代码。 sysread也继续工作。而不是sysread,我有一个睡眠30秒的perl脚本。我的超时设置为10秒。正如预期的那样,在#timed出来的代码被执行,但该脚本继续sleep.Any输入赞赏

回答

10

die不会导致进程结束,它会引发异常。

现在,如果没有发现异常,则会结束一个进程,但您已有code来捕获此异常。

该进程没有结束,因为你明确地阻止它结束。


由于您对所得到的行为并不十分清楚,因此可能存在另一种可能性:您正在使用Windows的Windows版本。

alarm是一个Unix系统调用。这是非常有用的(经过一段时间后发送信号)在Windows上没有意义,因为Windows没有信号。

Perl在某种程度上模仿alarm,但只能以非常有限的方式。 sleep很可能是唯一可以通过alarm中断的操作。否则,仅在语句之间检查超时。

因此它不会中断sysread,但是一旦sysread返回,Perl会注意到超时过期并模拟一个信号。

+0

@doon,添加了辅助的答案。 – ikegami 2012-04-18 09:55:59

+0

谢谢。我正在使用perl的UNIX版本。谢谢你让我知道死是一个例外。我没有意识到这一点, – doon 2012-04-18 10:44:47

+0

@doon,相反,有['出口](http://perldoc.perl.org/functions/exit.html)。但是,通常你想'死掉',因为它允许人们如果他们选择处理错误。 – ikegami 2012-04-18 19:55:12

1

男子报警

alarm() arranges for a SIGALRM signal to be delivered to the calling process in seconds seconds. 

SIGALARM交付执行到else块之前。在之前插入一个STDIN sysread这样sigalarm触发了预期的结果。

1

“相反sysread执行的,我有这样的睡了30秒的perl脚本。我 超时设置为10秒。正如预期的那样,#timed出的代码被执行 但脚本继续睡觉。 “

真的吗?

#!/usr/bin/perl 
use strict; 
use warnings FATAL => qw(all); 

eval { 
    open my $fh, '<', $0 || die; 
    local $SIG{ALRM} = sub { 
     print STDERR "hello!\n"; 
     die "bye!"; 
    }; 
    alarm 3; 
    while (<$fh>) { 
     print $_; 
     sleep 1; 
    } 
    close $fh; 
}; 

if ([email protected]) { 
    print "HERE: [email protected]\n"; 
} 

输出:

#!/usr/bin/perl 
use strict; 
use warnings FATAL => qw(all); 
hello! 
HERE: bye! at ./test.pl line 9, <$fh> line 3. 

超过在预期的3秒;如果我只是使用“睡眠100”而不是文件读取,情况仍然如此。注意,如果你产生一个子进程,报警不会杀死它,父进程必须等待。那样的话,“你好!”在信号处理程序中将出现警报触发时,但捕获死亡的eval将不会完成,直到子进程。

+0

谢谢。这很有用。你已经报警即睡眠习惯后写的代码是我做的S火焰。但它是在一个单独的脚本。感谢评论,eval不会完成,直到命令完成。虽然这很混乱。如果这在其脚本EVAL父进程结束,那么EVAL已经完成。我希望你能理解我的问题。评论框不允许我直观地解释。再次感谢 – doon 2012-04-18 10:44:05

+0

如果你用'打开我的$ fh'替换'open $ 0',' - ','sleep 10'||死亡;'你就会明白我由于必须等待一个子进程(壳睡眠)的意思。但否则,不,正常的命令不应该阻止警报。 – delicateLatticeworkFever 2012-04-18 12:53:28

0

我移植一个Linux Perl脚本Windows时有同样的问题。

我要解决它...

创建非阻塞套接字

$recsock = IO::Socket::INET->new(
          LocalPort => 68, 
          Proto => "udp", 
          Broadcast => 1, 
          Blocking => 0, 
          ) or die "socket: [email protected]"; 

添加$继续变量超时处理

# Timeout handle 
$SIG{ALRM} = sub { 
    print "timeout\n"; 
    $continue = 1; 
}; 

,并检查了$继续在发生超时时成为现实:

alarm($timeout); 
    while(1){ 
     $recsock->recv($newmsg, 1024); 
     eval { 
      $packet = Net::Package->new($newmsg); 
      ... 
     }; 
     sleep 0.1; 
     last if ($continue); 
    } 
    alarm(0);