perl报警与子进程

Mar*_*yer 6 windows perl

我有一个perl脚本,它运行一系列用于回归测试的批处理脚本.我想在批处理脚本上实现超时.我目前有以下代码.

    my $pid = open CMD, "$cmd 2>&1 |";
    eval {
               # setup the alarm
               local $SIG{ALRM} = sub { die "alarm\n" };
               # alarm on the timeout
               alarm $MAX_TIMEOUT;
               log_output("setting alarm to $MAX_TIMEOUT\n");

               # run our exe
               while( <CMD> ) {
                       $$out_ref .= $_;
               }
               $timeRemaining = alarm 0;
            };
            if ($@) {
                    #catch the alarm, kill the executable
            }
Run Code Online (Sandbox Code Playgroud)

问题是,无论我将最大超时设置为什么,警报都不会被触发.我尝试过使用Perl :: Unsafe :: Signals,但这没有帮助.

如果我想能够捕获它们的输出,这是执行批处理脚本的最佳方法吗?是否有另一种方法可以做同样的事情,允许我使用警报,或者除警报之外还有另一种方法可以使程序超时吗?

我已经构建了一个测试脚本来确认警报是否适用于我的perl和windows版本,但是当我运行这样的命令时它不起作用.

我在windows 7 x64上使用activeperl 5.10.1运行它.

mob*_*mob 4

很难判断什么时候alarm会起作用,系统调用什么时候会被打断SIGALRM,什么时候不会被打断,相同的代码在不同的操作系统上可能会有不同的行为等等。

如果您的作业超时,您想终止已启动的子进程。这是穷人警报的一个很好的用例:

my $pid = open CMD, "$cmd 2>&1 |";
my $time = $MAX_TIMEOUT;

my $poor_mans_alarm = "sleep 1,kill(0,$pid)||exit for 1..$time;kill -9,$pid";
if (fork() == 0) {
    exec($^X, "-e", $poor_mans_alarm);
    die "Poor man's alarm failed to start";  # shouldn't get here
}
# on Windows, instead of  fork+exec, you can say
#    system 1, qq[$^X -e "$poor_mans_alarm"]


...
Run Code Online (Sandbox Code Playgroud)

穷人的警报在一个单独的进程中运行。每一秒,它都会检查具有标识符的进程是否$pid仍然存在。如果进程不存在,则警报进程退出。如果进程在$time几秒钟后仍然存在,它会向进程发送一个终止信号(我使用 9 使其不可捕获,使用 -9 取出整个子进程树,您的需求可能会有所不同)。

exec实际上可能没有必要。我使用它是因为我还使用这个习惯用法来监视可能比启动它们的 Perl 脚本寿命更长的进程。因为这个问题不会出现这种情况,所以您可以跳过调用并exec

if (fork() == 0) {
    for (1..$time) { sleep 1; kill(0,$pid) || exit }
    kill -9, $pid;
    exit;
}
Run Code Online (Sandbox Code Playgroud)

反而。)