2016-11-17 6 views
2

Есть ли простой и надежный способ узнать, когда задача IPC::Run выполнена, то есть все дочерние процессы (ы) вышли?Как узнать, закончилось ли задание IPC :: Run

Документы удивительно молчат об этом.

Кажется, что зацикливание на pumpable работ, хотя это не совсем четко задокументировано как правильный способ делать вещи:

use strict; 
use warnings; 
use IPC::Run; 
use 5.12.0; 

my $handle = IPC::Run::start(['sleep', '10']); 

while ($handle->pumpable) 
{ 
    sleep(0.5); 
    # do other stuff in the event loop 
    # so we don't want to block on finish 
} 

$handle->finish; 

print("exited with '" . $handle->result . "'"); 

Есть ли лучший вариант? finish, но тогда вы не можете выполнять другую работу в цикле событий, пока вы ждете завершения процесса.

Я удивлен, что это не просто

$handle->running 

или

$handle->finished 

Я пропускаю что-то очевидное?

Аналогичным образом, как представляется, не существует документального способа получения pid ребенка (ren).

+0

Блоки '$ handle-> finish', такие как' wait'. Если вы хотите проверить перед ожиданием, вызов завершенного результата 'result'_before_ явно выдает исключение, поэтому вы можете использовать это, проверив исключение -' eval {$ res = $ handle-> result} или напечатав "Still running \ п ";'. Это kludge (нужно проверить '$ @' вместо 'or'-it), но это будет? Существует ряд других версий «результата». Там также есть «сигнал», и я попытался отправить «0», но ничего не возвращаю. Кажется, в документах есть намек на то, что pid не может быть напрямую. – zdim

+0

Ugh. Да, можно попробовать вызвать «результат» и захватить исключение. Ужасно :(Я должен был быть явным, что я ищу неблокирующий способ, иначе я бы просто использовал 'IPC :: Run :: run'. Спасибо. –

+0

Правильно, я получил это, но сказал блокировка на всякий случай. Ужасно, но сейчас я не вижу более чистого пути (я не использовал этот модуль много. Я буду смотреть больше, поскольку я всегда хотел проверить его лучше.) – zdim

ответ

1

Я не смог найти чистый способ сделать это, только другими способами.

Сведения о том, могут ли дети работать, могут быть получены result и pumpable (что уже используется в вопросе).

Метод result «Выдает исключение, если передается дочерний номер за пределами диапазона». Это происходит, если мы запрашиваем, когда дети еще не вышли. Таким образом, с помощью одного дочернего процесса

sub only_kid_finished { eval { $_[0]->result }; return [email protected] ? 0 : 1 } 

еще лучше, results метод возвращает список значений выхода ребенка, а также «Выдает исключение, если жгут не в готовом состоянии». Таким образом, его можно использовать одинаково, но с большим количеством детей он также может использоваться для отслеживания того, сколько осталось/осталось.

Использованный в этом вопросе, pumpable может также сообщить ли работают какие-либо процессы

sub any_kids_left { return $_[0]->pumpable } 

Это относится к каналам ввода/вывода или процессов, но если что-то работает, оно должно возвращать верно, иначе ложь.

Вопрос о детском PID для меня немного раздражает, так как это информация, которую, возможно, нужно знать. Хотя это правильно в объекте, $handle->{KIDS}[0]{PID} (для первого ребенка), я не вижу, как получить его разумным способом. Я бы подумал, что структура, эта базовая, не может измениться, поэтому она соблазнит меня использовать ее с проверками. Тогда я был бы доволен тем, что мог, заслужив это.

После получения PID можно проверить процесс с помощью kill 0, $pid.Обратите внимание, что это возвращает true (1), пока процесс не был получен (даже когда он вышел, но является зомби).

1

Вот обходной путь для получения ПИД-регулятора. Затем вы можете подождать ребенка или настроить обработчик SIGCHLD. Например:

use feature qw(say); 
use strict; 
use warnings; 

use IPC::Run qw(start); 
use Proc::ProcessTable; 

my $h = start ['sleep', '5']; 

my $pt = Proc::ProcessTable->new(); 
my $kid; 
for my $p (@{ $pt->table }){ 
    if ($p->ppid == $$) { 
     if ($p->cmndline =~ m{/bin/sleep}) { 
      $kid = $p->pid; 
     } 
    } 
} 

if (defined $kid) { 
    say "Waiting for child with PID '$kid' to finish.."; 
    waitpid $kid, 0; 
    say "Done."; 
} 
else { 
    die "Could not find PID of child process\n"; 
} 
Смежные вопросы