2

Windows で一連の他のプログラムを実行する Perl スクリプトを作成しようとしています。プロセスの stdout、stderr、および終了コードをキャプチャできる必要があり、プロセスが割り当てられた実行時間を超えているかどうかを確認できる必要があります。現在、私のコードの関連部分は次のようになっています。

...
        $pid = open3($wtr, $stdout, $stderr, $command);
        if($time < 0){
            waitpid($pid, 0);
            $return = $? >> 8;
            $death_sig = $? & 127;
            $core_dump = $? & 128;
        }
        else{
            # Do timeout stuff, currently not working as planned
            print "pid: $pid\n";
            my $elapsed = 0;
            #THIS LOOP ONLY TERMINATES WHEN $time > $elapsed ...?
            while(kill 0, $pid and $time > $elapsed){
                Time::HiRes::usleep(1000);  # sleep for milliseconds
                $elapsed += 1;
                $return = $? >> 8;
                $death_sig = $? & 127;
                $core_dump = $? & 128;
            }
            if($elapsed >= $time){
                $status = "FAIL";
                print $log "TIME LIMIT EXCEEDED\n";
            }
        }
        #these lines are needed to grab the stdout and stderr in arrays so 
        #  I may reuse them in multiple logs
        if(fileno $stdout){
            @stdout = <$stdout>;
        }
        if(fileno $stderr){
            @stderr = <$stderr>;
        }
...

すべてが正常に機能している場合$time = -1(タイムアウトは必要ありません)、システムはそれkill 0, $pidを常に 1 と見なします。これにより、許可されている時間全体にわたってループが実行されます。

わかりやすくするために、いくつかの追加の詳細を示します。

  • これは Windows で実行されています。
  • 期待される出力をすべて取得したため、プロセスが終了することはわかっています。
  • Perl バージョン: これは、MSWin32-x86-multi-thread 用にビルドされた v5.10.1 の perl です (2 つの登録済みパッチがあります。詳細については、perl -V を参照してください) Copyright 1987-2009, Larry Wall Binary build 1007 [291969] provided by ActiveState http ://www.ActiveState.com 2010 年 1 月 26 日23:15:11 に構築
  • 私はあなたの助けに感謝します:D

同様の問題を抱えている可能性のある将来の人のため に、コードが機能するようになりました。変更されたコードセクションは次のとおりです。

        $pid = open3($wtr, $stdout, $stderr, $command);
        close($wtr);
        if($time < 0){
            waitpid($pid, 0);
        }
        else{
            print "pid: $pid\n";
            my $elapsed = 0;
            while(waitpid($pid, WNOHANG) <= 0 and $time > $elapsed){
                Time::HiRes::usleep(1000);  # sleep for milliseconds
                $elapsed += 1;
            }

            if($elapsed >= $time){
                $status = "FAIL";
                print $log "TIME LIMIT EXCEEDED\n";
            }
        }
        $return = $? >> 8;
        $death_sig = $? & 127;
        $core_dump = $? & 128;
        if(fileno $stdout){
            @stdout = <$stdout>;
        }
        if(fileno $stderr){
            @stderr = <$stderr>;
        }
        close($stdout);
        close($stderr);
4

1 に答える 1

4

の代わりにkill 0、次を使用しますwaitpid $pid, WNOHANG

use POSIX qw( WHOHANG );

if (waitpid($pid, WNOHANG) > 0) {
   # Process has ended. $? is set.
   ...
}
于 2012-11-09T22:34:16.117 に答える