我试图在使用system()
的Perl脚本中运行应用程序。我正在运行的应用程序有时会卡住(它会进入某种无限循环)。有没有一种方法可以让我知道这个应用程序是否被卡住并杀死它继续使用Perl脚本?在Perl中使用system()启动应用程序开始
我试图做这样的事情:
start testapp.exe;
if(stuck with testapp.exe) {
kill testapp.exe;
}
我试图在使用system()
的Perl脚本中运行应用程序。我正在运行的应用程序有时会卡住(它会进入某种无限循环)。有没有一种方法可以让我知道这个应用程序是否被卡住并杀死它继续使用Perl脚本?在Perl中使用system()启动应用程序开始
我试图做这样的事情:
start testapp.exe;
if(stuck with testapp.exe) {
kill testapp.exe;
}
确定“它是否陷入无限循环”被称为Halting Problem并且是不可判定的。
如果你想杀死它,你将不得不使用fork
来分割应用程序,如果它太长了,就从另一个分支中杀掉它。
您可以确定proccess会太久本
use POSIX ":sys_wait_h";
waitpid($pid, WNOHANG)>0 #waitpid returns 0 if it still running
至少,根据this manual page
我不知道它有多好作品在各种系统上,你可以尝试出。
不是一个直接的答案,但我可以推荐使用forks
模块,如果你想轻松到餐桌,但它的工作原理只在UNIX系统(不窗口)。
OK,更有助于代码:)它的工作原理在UNIX,根据perlfork的perldoc,它应该工作在Windows上完全相同的方式。
use warnings;
use strict;
use POSIX ":sys_wait_h";
my $exited_cleanly; #to this variable I will save the info about exiting
my $pid = fork;
if (!$pid) {
system("anything_long.exe"); #your long program
} else {
sleep 10; #wait 10 seconds (can be longer)
my $result = waitpid(-1, WNOHANG); #here will be the result
if ($result==0) { #system is still running
$exited_cleanly = 0; #I already know I had to kill it
kill('TERM', $pid); #kill it with TERM ("cleaner") first
sleep(1); #wait a bit if it ends
my $result_term = waitpid(-1, WNOHANG);
#did it end?
if ($result_term == 0) { #if it still didnt...
kill('KILL', $pid); #kill it with full force!
}
} else {
$exited_cleanly = 1; #it exited cleanly
}
}
#you can now say something to the user, for example
if (!$exited_cleanly) {...}
您不能确定,如果你执行它像应用程序被套牢,因为system
语句不会返回,直到应用程序终止。
至少,您需要启动测试应用程序,以便它可以从要监视它的Perl脚本异步运行。
解决了这部分问题后,您必须建立一种机制,允许监视Perl脚本确定应用程序被卡住。这是一个非平凡的练习,并且可能依赖于系统,除非您采用简单的权宜之计,例如要求应用程序在某处写入心跳指示,并且Perl脚本监视心跳。例如(不一定是一个很好的例子),应用程序可以将当前时间写入由PID标识的文件中,并且Perl脚本可以监视该文件以查看心跳是否足够近。当然,这假定'无限循环'不包括写入心跳文件的代码。
那么你可以建议一些其他的方法来启动应用程序,可以帮助我确定应用程序的状态吗? – int80h
标准方法是使用'fork'并让子'exec'为应用程序,而父代监视孩子。 OTOH,这是微不足道的;从外部确定测试应用程序内部发生了什么是很难的。 –
暂停问题的一般解决方案对此非常有用;-) – BRFennPocock
system("start testapp")
是短期的
system("cmd", "/c", "start testapp")
的Perl只是知道cmd
;它不知道任何关于start
,更不用说关于testapp
。 system
不是你想要的工具。这是第一个问题。
第二个问题是,你还没有定义什么意思是“卡住”。如果你想监视一个程序,它需要一个心跳。心跳是可以从外部检查的周期性活动。它可以写入管道。它可以改变一个文件。任何东西。
监控程序会监听这个心跳,并假定如果心脏停止跳动,程序就会死机,可以这么说。
“被害”在UNIX上使用的信号完成的,但它在Windows中使用TerminateProcess
完成。第三个问题是Perl核心不允许你访问该函数。
第一个和第三个问题的解决方案是Win32::Process。它允许你在后台启动一个进程,它也允许你终止它。
创建心跳取决于您。
如果你知道testapp不应该花费超过N秒的时间来完成它的事情,那么你可以通过这种方法来处理这个问题,然后你可以通过IPC::Run来使用超时来终止应用程序。
在下面的示例中,会有1秒的超时时间,其中杀死sleep 10
命令花费的时间太长(超过1秒的超时时间)。如果这不符合你的要求,那么你应该提供更多关于如何检测testapp.exe“卡住”的信息。
#!/usr/bin/env perl
use IPC::Run qw(run timeout);
eval { # if (stuck with testapp.exe for more than N seconds)
@cmd = ('sleep', '10'); # this could be testapp.exe instead of sleep
run \@cmd, \$in, \$out, \$err, timeout(1) or die "test"; # start testapp.exe
print "do stuff if cmd succeeds\n";
};
print "more stuff to do afterwards whether or not command fails or succeeds\n";
“有没有一种方法可以让我知道......”......其实,这听起来好像你有某种方式知道它“卡住”了。你是否决定用手?基于运行时间过长的程序,或者反复输出某个输出,或者...? – BRFennPocock