【问题标题】:Why doesn't waitpid wait for the process to exit?为什么waitpid不等待进程退出?
【发布时间】:2015-02-24 22:38:21
【问题描述】:

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

问题

如何让waitpid 仅在我提供的 pid 退出时继续?

#!/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 并且永远不会退出。

【问题讨论】:

    标签: linux perl waitpid


    【解决方案1】:

    wait 系列函数仅适用于子进程,即使是 waitpid。睡眠过程不是你的孩子,而是你孩子的孩子。这是因为system 本质上是fork + exec。通过使用 Parallel::ForkManager + system 你正在分叉,然后再次分叉,然后执行睡眠。

    既然你已经分叉了,你应该使用 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 没有意识到 $pm->start 已经分叉,因此必须禁止来自 Perl 的警告“不可能达到声明”。这应该是 no warnings "exec" 但这不起作用,所以我不得不将它们全部压制。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-01-15
      • 2021-09-24
      • 1970-01-01
      • 2023-03-13
      • 1970-01-01
      相关资源
      最近更新 更多