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 は引き続き機能します。sysread の代わりに、30 秒間スリープする perl スクリプトを用意しました。私のタイムアウトは10秒に設定されていました。予想どおり、#timed out のコードは実行されますが、スクリプトは引き続きスリープ状態になります。

4

4 に答える 4

10

dieプロセスを終了させるのではなく、例外をスローします。

ここで、何も例外をキャッチしない場合、プロセスは終了しますが、この例外をキャッチするコードが用意されています。

プロセスの終了を明示的に防止しているため、プロセスは終了しません。


どのような動作が得られるのかはっきりしないため、別の可能性があります: Perl の Windows ビルドを使用している可能性があります。

これalarmは Unix システム コールです。Windowsにはシグナルがないため、これはまさに目的(一定の時間が経過した後にシグナルを送信する)は意味がありません。

Perl はalarmある程度エミュレートしますが、非常に限られた方法でしかエミュレートできません。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

「sysread の代わりに、30 秒間スリープする perl スクリプトがありました。タイムアウトは 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」を使用した場合でも当てはまります。サブプロセスを生成した場合、アラームはそれを強制終了せず、親プロセスは待機する必要があることに注意してください。その場合は「こんにちは!」アラームが発生するとシグナルハンドラに表示されますが、ダイをキャッチする評価はサブプロセスが完了するまで完了しません。

于 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 が true になることを確認します。

    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 に答える