perl与subprocess报警

我有一个Perl脚本,运行一系列批处理脚本进行回归testing。 我想在批处理脚本上实现一个超时。 我目前有以下代码。

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 } 

问题是,无论我设置最大超时时间,警报都不会被触发。 我试过使用Perl :: Unsafe :: Signals,但没有帮助。

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

我已经构build了一个testing脚本来确认报警在我的perl和windows版本上运行,但是当我像这样运行一个命令时,它不起作用。

我在windows 7 x64上使用activeperl 5.10.1来运行这个。

当系统调用不会被SIGALRM中断,相同的代码在不同的操作系统上表现如何不同时,很难说出什么时候会发生alarm

如果你的工作超时,你想杀死你已经开始的子进程。 对于这个可怜的人来说,这是一个很好的用例:

 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"] ... 

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

exec实际上可能不是必须的,我使用它,因为我也使用这个成语来监视那些可能比它启动的Perl脚本更长的进程,因为这个问题不会出现,所以你可以跳过exec调用,说

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

代替。)