Почему waitpid не ждет завершения процесса?

В приведенном ниже сценарии я пытаюсь выяснить, как waitpid работает, но не ждет ssh процесс для выхода. done печатается сразу, а не после ssh процесс существует.

Вопрос

Как сделать waitpid только продолжить, когда пид, который я даю, вышел?

#!/usr/bin/perl
use strict;
use warnings;
use Parallel::ForkManager;
use POSIX ":sys_wait_h";

my $pm = Parallel::ForkManager->new(5);
my $pid = $pm->start;
my $p = $pid;
if (!$pid) {
    system("ssh 10.10.47.47 sleep 10");
    $pm->finish;
}

$p = qx(/usr/bin/pgrep -P $p);
print "ssh pid is $p\n";

my $kid;
do {
    $kid = waitpid($p, 0);
} while $kid > 0;

print "done\n";

Я также пытался

while (1) {
    $p = kill 0, $p;
    print "x";
    sleep 1 if $p;
    print "*";
    last unless $p;
}

но он даже не достигает первого print по какой-то причине и никогда не выходит.

1 ответ

Решение

wait Семейство функций работает только на дочерние процессы, даже waitpid, Процесс сна - это не ваш ребенок, это ребенок вашего ребенка. Это потому что system по существу fork + exec, Используя систему Parallel::ForkManager +, вы разветвляетесь, затем снова разветвляетесь, затем выполняете режим сна.

Поскольку вы уже разветвились, вы должны использовать exec. Это дает дополнительное преимущество, заключающееся в отсутствии необходимости вызова pgrep и проблем с синхронизацией (т. Е. Возможно, родитель вызовет pgrep до того, как дочерний элемент выполнит систему).

my $pm = Parallel::ForkManager->new(5);
my $pid = $pm->start;
my $p = $pid;
if (!$pid) {
    no warnings;  # no warnings "exec" is not working
    exec("sleep 10");
    $pm->finish;
}

print "sleep pid is $p\n";
waitpid($p, 0);

Для простоты сейчас используется сон. Предупреждение от Perl о том, что "заявление вряд ли будет достигнуто" должно быть подавлено, потому что Perl не осознает $pm->start раздвоился Это должно быть no warnings "exec" но это не работает, поэтому я должен был подавить их всех.

Другие вопросы по тегам