3

从如何指定 Perl 系统调用的超时限制?

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

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

4

4 回答 4

10

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

现在,如果没有捕获到异常,则结束一个进程,但是您有适当的代码来捕获这个异常。

该过程不会结束,因为您明确阻止它结束。


由于您不太清楚自己得到了什么行为,因此可能还有另一种可能性:您正在使用 Windows 构建的 Perl。

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

Perlalarm在某种程度上进行了模拟,但只是以非常有限的方式。sleep很可能是唯一可以被alarm. 否则,仅在语句之间检查超时。

所以它不会中断sysread,但是一旦sysread返回,Perl 会注意到超时时间已过,然后模拟一个信号。

于 2012-04-18T09:48:02.470 回答
1

人警报

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

在传递sigalarm之前,执行到达 else 块。在sysread之前插入STDIN ,以便sigalarm触发产生预期结果。

于 2012-04-18T07:54:10.270 回答
1

“我有一个休眠 30 秒的 perl 脚本,而不是 sysread。我的超时设置为 10 秒。正如预期的那样,#timed out 中的代码已执行,但脚本继续休眠。”

真的吗?

#!/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 ($@) {
    print "HERE: $@\n";
}

输出:

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

在预期的 3 秒内结束;如果我只使用“sleep 100”而不是读取文件,情况仍然如此。请注意,如果您生成子进程,则警报不会杀死该子进程,并且父进程必须等待。在这种情况下,“你好!” 当警报触发时,信号处理程序中将出现,但捕获骰子的 eval 将在子进程完成之前完成。

于 2012-04-18T08:27:04.523 回答
0

在将 Linux Perl 脚本移植到 Windows 时,我遇到了同样的问题。

我通过...解决了

创建非阻塞套接字

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

将 $continue 变量添加到超时句柄

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

并在超时发生时检查 $continue 是否变为真:

    alarm($timeout);
     while(1){
         $recsock->recv($newmsg, 1024);
         eval {
            $packet = Net::Package->new($newmsg); 
             ...
        };
        sleep 0.1;
        last if ($continue);
    }
    alarm(0);
于 2013-06-24T11:50:14.720 回答