杀死挂起的子进程
我的 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";
到目前为止,它确实中止了子进程,但后来我修改了外部程序并使其仅休眠了 5 秒。应该在之前完成上面代码中指定的 10 秒超时及其 stdout
输出应该被捕获到变量 $out
中,但上面的脚本没有输出任何内容! 任何想法如何正确地做到这一点?
(修复有缺陷的外部程序不是一个选项。)提前致谢。
My Perl script runs an external program (which takes a single command-line parameter) and processes its output. Originally, I was doing this:
my @result = `prog arg`;
However, turns out that the program is buggy and hangs unpredictably in rare cases. How can I kill the program if it hasn't exited after a certain amount of time? The script has to work both in Windows and in Linux, and it is my understanding that alarms and forks don't work well (or at all) in Windows.
I found a module called IPC::Run but I can't figure out how to use it properly from its documentation. :-( I tried this:
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;
As a test, I created a program that just sleeps 60 seconds, prints a string to stdout
and exits. When I try to run it with the above code, it hangs for 60 seconds (instead of for 10 seconds, as specified in the timeout) and aborts with a bizarre error:
IPC::Run: timeout on timer #1 at C:/Bin/Unix/Perl/site/lib/IPC/Run.pm line 2956
Then I found another module, Proc::Reliable. From the description, it seems to do precisely what I want. Except that it doesn't work! I tried this:
use strict;
use warnings;
use Proc::Reliable;
my $proc = Proc::Reliable->new ();
$proc->maxtime (10);
my $out = $proc->run ("prog arg");
print "$out\n";
It indeed aborts the child process after 10 seconds. So far, so good. But then I modified the external program and made it sleep for only 5 seconds. This means that the program should finish before the 10-second timeout specified in the above code and its stdout
output should be captured into the variable $out
. But it isn't! The above script doesn't output anything.
Any ideas how to do it properly? (Fixing the buggy external program is not an option.) Thanks in advance.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
尝试穷人的警报
穷人的警报在单独的进程中运行。每秒,它都会检查标识符为 $pid 的进程是否仍然存在。如果进程不存在,则警报进程退出。如果进程在 $time 秒后仍然存在,它会向进程发送一个终止信号(我使用 9 使其不可捕获,使用 -9 取出整个子进程树,您的需求可能会有所不同。
kill 9,。 ..
也是可移植的)。编辑:如何捕获穷人警报过程的输出?
不使用反引号——那么您将无法获取进程 ID,并且如果进程超时并被终止,您可能会丢失中间输出。替代方案是
1) 将输出发送到文件,在进程完成时读取文件
2) 使用 Perl 的
open
启动进程while
循环将在进程完成时结束自然或不自然地结束。Try the poor man's alarm
The poor man's alarm runs in a separate process. Every second, it checks whether the process with identifier $pid is still alive. If the process isn't alive, the alarm process exits. If the process is still alive after $time seconds, it sends a kill signal to the process (I used 9 to make it untrappable and -9 to take out the whole subprocess tree, your needs may vary.
kill 9,...
is also portable).Edit: How do you capture the output of the process with the poor man's alarm?
Not with backticks -- then you can't get the process id and you may lose the intermediate output if the process times out and gets killed. The alternatives are
1) send output to a file, read the file when the process is done
2) use Perl's
open
to start the processThe
while
loop will end when the process ends, either naturally or unnaturally.这是我能做的最好的了。任何有关如何避免在 Windows 上使用临时文件的想法将不胜感激。
This is the best I could do. Any ideas on how to avoid the use of a temporary file on Windows would be appreciated.
您可能想使用警报系统调用,如 perldoc -f Alarm。
You may want to use alarm system call as in perldoc -f alarm.