Убийство приложения началось с использованием system () в Perl - PullRequest
2 голосов
/ 12 декабря 2011

Я пытаюсь запустить приложение внутри скрипта Perl, используя system().Приложение, которое я запускаю, иногда зависает (оно входит в какой-то бесконечный цикл).Есть ли способ узнать, зависло ли это приложение, и убить его, чтобы продолжить работу со скриптом Perl?

Я пытаюсь сделать что-то вроде этого:

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

Ответы [ 4 ]

2 голосов
/ 12 декабря 2011

Определение того, называется ли оно «застрявшим в бесконечном цикле» Проблема останова и неразрешимо.

Если вы хотите убить его, вам придется форкнуть приложение, используя fork и затем убейте его с другого форка, если он идет слишком долго.

Вы можете определить, будет ли процесс идти слишком долго, по крайней мере, по этому

use POSIX ":sys_wait_h";
waitpid($pid, WNOHANG)>0 #waitpid returns 0 if it still running

, согласнона эту страницу руководства

Я не уверен, насколько хорошо она работает в различных системах, вы можете попробовать.

Не прямой ответ, но я могу рекомендовать использоватьМодуль forks, если вы хотите с легкостью форкнуть, но он работает только в системах UNIX ( не windows).


ОК, больше кода помощи:) Он работает в 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) {...} 
1 голос
/ 12 декабря 2011

Вот один из способов справиться с проблемой, если вы знаете, что 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";
1 голос
/ 12 декабря 2011
system("start testapp")

- это сокращение от

system("cmd", "/c", "start testapp")

Perl просто знает о cmd;он ничего не знает о start, а тем более о testapp.system это не тот инструмент, который вам нужен.Это первая проблема.


Вторая проблема заключается в том, что вы не определили, что значит «застрять».Если вы хотите следить за программой, ей нужно сердцебиение.Сердцебиение - это периодическая деятельность, которая может быть исследована извне.Это может быть запись в трубу.Это может быть изменение файла.Все, что угодно.

Программа мониторинга прослушивает это сердцебиение и предполагает, что программа мертва, если, так сказать, перестает биться сердце.


"Убийство" выполняется с использованием сигналов в unix, но это делается с помощью TerminateProcess в Windows.Третья проблема заключается в том, что ядро ​​Perl не дает вам доступа к этой функции.


Решение первой и третьей проблемы - Win32 :: Process .Он позволяет запускать процесс в фоновом режиме, а также прерывать его.

Создание пульса зависит от вас.

0 голосов
/ 12 декабря 2011

Вы не можете определить, что приложение застряло, если вы выполните его таким образом, потому что оператор system не вернется, пока приложение не завершится.

Итак, по крайней мере, вам нужно запустить тестовое приложение, чтобы оно могло асинхронно запускаться из сценария Perl, который должен его отслеживать.

Решив эту часть проблемы, вы должны установить механизм, который позволит мониторинговому Perl-скрипту определять, что приложение зависло. Это нетривиальное упражнение, и, скорее всего, оно зависит от системы, если только вы не примете простой прием, такой как требование приложения написать где-нибудь индикацию сердцебиения, и сценарий Perl отслеживает сердцебиение. Например (не обязательно хороший пример), приложение может записать текущее время в файл, идентифицируемый его идентификатором PID, а сценарий Perl может отслеживать файл, чтобы определить, достаточно ли недавнее сердцебиение. Конечно, это предполагает, что «бесконечный цикл» не включает в себя код, который записывает в файл сердцебиения.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...