2014-12-28 6 views
8

Im folgenden Skript versuche ich herauszufinden, wie waitpid funktioniert, aber es wartet nicht auf ssh Prozess zu beenden. done wird sofort gedruckt und nicht nach dem ssh Prozess existiert.Warum warten Sie nicht, bis der Prozess beendet wird?

Frage

Wie ich waitpid nur machen weiter, wenn die pid ich es verlassen haben, geben?

#!/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"; 

Ich habe auch versucht,

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

aber es erreicht nicht einmal die erste print aus irgendeinem Grund und nie verlässt.

Antwort

8

Die wait Familie von Funktionen funktioniert nur auf untergeordneten Prozessen, auch waitpid. Der Schlafprozess ist nicht dein Kind, es ist das Kind deines Kindes. Dies liegt daran, system ist im Wesentlichen fork + exec. Wenn Sie das Parallel :: ForkManager + -System verwenden, verzweigen Sie, forkieren Sie erneut und führen Sie dann den Ruhezustand aus.

Da Sie bereits gegabelt haben, sollten Sie exec verwenden. Dies hat den zusätzlichen Vorteil, dass der Aufruf von pgrep und sein Timing-Problem nicht benötigt wird (dh es ist möglich, dass der Elternteil pgrep aufruft, bevor das Kind das System ausgeführt hat).

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); 

Der Einfachheit halber wird jetzt Schlaf verwendet. Eine Warnung von Perl, dass "Statement wahrscheinlich nicht erreicht wird" muss unterdrückt werden, da Perl $pm->start nicht gespalten hat. Dies sollte no warnings "exec" sein, aber das funktioniert nicht, also musste ich sie alle unterdrücken.