为什么没有waitpid等待进程退出?

时间:2014-12-28 13:57:53

标签: linux perl waitpid

在下面的脚本中,我试图找出waitpid的工作原理,但它不会等待ssh进程退出。 done会立即打印,而不是在ssh进程存在之后。

问题

如果我提出的{pid}已经退出,我只能继续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 个答案:

答案 0 :(得分:8)

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",但这不起作用所以我不得不全部压制它们。

相关问题