perl – 杀死一个挂起的孩子

我的Perl脚本运行一个外部程序(它接受一个命令行参数)并处理其输出.最初,我这样做:
my @result = `prog arg`;

然而,事实证明该程序是错误的,并且在极少数情况下会无法预测.如果程序在一段时间后没有退出,我怎么能杀掉它呢?该脚本必须在Windows和Linux中都能正常工作,我的理解是警报和分支在Windows中不能正常工作(或根本不能).

我找到了一个名为IPC::Run的模块,但我无法从文档中弄清楚如何正确使用它. :-(我试过这个:

use strict;
use warnings;
use IPC::Run qw(run timeout);
my $in;
my $out;
my $err;
my @result;
my @cmd = qw(prog arg);
run \@cmd,\$in,\$out,\$err,timeout (10) or die "@cmd: $?";
push @result,$_ while (<$out>);
close $out;
print @result;

作为测试,我创建了一个只能睡60秒的程序,将字符串打印到stdout并退出.当我尝试使用上面的代码运行它时,它会挂起60秒(而不是10秒,如超时中所指定的)并以奇怪的错误中止:

IPC::Run: timeout on timer #1 at C:/Bin/Unix/Perl/site/lib/IPC/Run.pm line 2956

然后我找到了另一个模块,Proc::Reliable.从描述中,它似乎正是我想要的.除了它不起作用!我试过这个:

use strict;
use warnings;
use Proc::Reliable;

my $proc = Proc::Reliable->new ();
$proc->maxtime (10);
my $out = $proc->run ("prog arg");
print "$out\n";

它确实在10秒后中止了子进程.到现在为止还挺好.但后来我修改了外部程序,让它只睡了5秒钟.这意味着程序应该在上面代码中指定的10秒超时之前完成,并且应该将其stdout输出捕获到变量$out中.但事实并非如此!上面的脚本没有输出任何内容.

任何想法如何正确地做到这一点? (修复有缺陷的外部程序不是一种选择.)在此先感谢.

解决方法

试试穷人的警报
my $pid;
if ($^O eq 'MSWin32') {
    $pid = system 1,"prog arg";    # Win32 only,run proc in background
} else {
    $pid = fork();
    if (defined($pid) && $pid == 0) {
        exec("proc arg");
    }
}

my $poor_mans_alarm = "sleep 1,kill(0,$pid)||exit for 1..$TIMEOUT;kill -9,$pid";
system($^X,"-e",$poor_mans_alarm);

穷人的警报在一个单独的过程中运行.每秒,它检查标识符$pid的进程是否仍然存在.如果进程未处于活动状态,则退出警报进程.如果在$time秒后进程仍处于活动状态,它会向进程发送一个kill信号(我使用9来使其无法访问,-9用于取出整个子进程树,你的需求可能会有所不同.要杀9,…是还便携).

编辑:如何用穷人的警报捕获进程的输出
没有反引号 – 那么你不能获得进程ID,如果进程超时并被杀死,你可能会失去中间输出.替代方案是

1)将输出发送到文件,在完成该过程时读取文件

$pid = system 1,"proc arg > some_file";
... start poor man's alarm,wait for program to finish ...
open my $fh,'<','some_file';
my @process_output = <$fh>;
...

2)使用Perl的open来启动该过程

$pid = open my $proc,'-|','proc arg';
if (fork() == 0) {
    # run poor man's alarm in a background process
    exec($^X,'-e',"sleep 1,kill 0,$pid||exit ...");
}
my @process_output = ();
while (<$proc>) {
   push @process_output,$_;
}

while循环将在过程结束时结束,无论是自然还是不自然.

相关文章

1. 如何去重 #!/usr/bin/perl use strict; my %hash; while(...
最近写了一个perl脚本,实现的功能是将表格中其中两列的数据...
表的数据字典格式如下:如果手动写MySQL建表语句,确认麻烦,...
巡检类工作经常会出具日报,最近在原有日报的基础上又新增了...
在实际生产环境中,常常需要从后台日志中截取报文,报文的形...
最近写的一个perl程序,通过关键词匹配统计其出现的频率,让...