在Perl中使用system()开始杀死应用程序

时间:2011-12-12 01:28:32

标签: perl

我正在尝试使用system()在Perl脚本中运行应用程序。我正在运行的应用程序有时会卡住(它会进入某种无限循环)。有没有办法可以知道这个应用程序是否被卡住并将其终止以继续使用Perl脚本?

我正在尝试做这样的事情:

start testapp.exe;
if(stuck with testapp.exe) {
    kill testapp.exe;
}

4 个答案:

答案 0 :(得分:2)

确定“它是否陷入无限循环”被称为Halting Problem并且是不可判定的。

如果你想杀死它,你将不得不使用fork分叉应用程序,然后从另一个分支中删除它,如果它太长了。

您可以通过此

确定过程进展太久
use POSIX ":sys_wait_h";
waitpid($pid, WNOHANG)>0 #waitpid returns 0 if it still running

至少,根据this manual page

我不确定它在各种系统上的效果如何,你可以尝试一下。

不是直接的答案,但我建议您使用forks模块,如果您想轻松分叉,但它在UNIX系统上只能 窗口)。


好的,更多帮助代码:)根据perlfork perldoc的说法,它适用于UNIX,它应该在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) {...} 

答案 1 :(得分:1)

system("start testapp")

的缩写
system("cmd", "/c", "start testapp")

Perl只知道cmd;它对start一无所知,更不用说testapp了。 system不是您想要的工具。这是第一个问题。


第二个问题是你没有定义“卡住”意味着什么。如果要监视程序,则需要心跳。心跳是一种可以从外部检查的周期性活动。它可以写入管道。它可以更改文件。任何东西。

监控程序会监听此心跳,并假设心脏停止跳动,程序已经死亡,可以这么说。


“杀戮”是使用unix中的信号完成的,但是在Windows中使用TerminateProcess完成。第三个问题是Perl核心不允许您访问该功能。


第一个和第三个问题的解决方案是Win32::Process。它允许您在后台启动进程,它还允许您终止它。

创建心跳取决于你。

答案 2 :(得分:1)

如果你知道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";

答案 3 :(得分:0)

如果您执行此操作,则无法确定应用程序是否卡住了,因为system语句在应用程序终止之前不会返回。

所以,至少,您需要启动测试应用程序,以便它可以从要监视它的Perl脚本异步运行。

解决了问题的这一部分后,您必须建立一种机制,允许监视Perl脚本以确定应用程序被卡住了。这是一项非常重要的练习,并且可能依赖于系统,除非您采用一种简单的权宜之计,例如要求应用程序在某处编写心跳指示,并且Perl脚本监视心跳。例如(不一定是一个很好的例子),应用程序可以将当前时间写入由其PID标识的文件中,并且Perl脚本可以监视文件以查看心跳是否足够近。当然,这假设“无限循环”不包括写入心跳文件的代码。