从Perl收获子进程

EMi*_*ler 10 perl fork parent-child waitpid

我有一个产生一组孩子的脚本.家长必须等待每个孩子完成.

我的脚本执行类似于以下perl脚本:

#! /usr/bin/perl
use strict;
use warnings;

print "I am the only process.\n";

my @children_pids;

for my $count (1..10){
        my $child_pid = fork();
        if ($child_pid) {  # If I have a child PID, then I must be the parent
                push @children_pids, $child_pid;
        }
        else { # I am the child
                my $wait_time = int(rand(30));
                sleep $wait_time;
                my $localtime = localtime;
                print "Child: Some child exited at $localtime\n";
                exit 0; # Exit the child
        }
}

foreach my $child (@children_pids) {
        print "Parent: Waiting on $child\n";
        waitpid($child, 0); 
        my $localtime = localtime;
        print "Parent: Child $child was reaped - $localtime.\n";
}

print "All done.\n";
Run Code Online (Sandbox Code Playgroud)

与我上面提供的代码类似,每个孩子可能需要不同的时间才能完成.

问题是当我尝试通过循环子PID时收获子foreach节点,在最后一个块中,父节点按照创建它们的顺序等待子节点.

显然,孩子们没有按照他们产生的顺序完成,所以我留下了一堆僵尸过程,这些过程恰好提前完成.

在我的实际代码中,这些孩子可能会在彼此之前完成几天,并且漂浮在周围的僵尸进程的数量可以增加到数百个.

我有更好的方法来收获一组孩子吗?

Bor*_*din 12

如果您的父进程不需要知道其子进程的完成状态,那么您可以设置

$SIG{CHLD} = 'IGNORE';
Run Code Online (Sandbox Code Playgroud)

这将在他们完成时自动收获所有孩子.

如果确实需要通知子项完成,则需要设置信号处理程序以获取所有可能的进程

use POSIX ();

$SIG{CHLD} = sub {
  while () {
    my $child = waitpid -1, POSIX::WNOHANG;
    last if $child <= 0;
    my $localtime = localtime;
    print "Parent: Child $child was reaped - $localtime.\n";
  }
};
Run Code Online (Sandbox Code Playgroud)


run*_*rig 6

使用"-1"表示pid,或使用wait()函数,等待任何子进程.收到的pid会被退回,因此您可以根据需要在列表中进行检查.如果这是不可接受的,那么定期使用POSIX :: WNOHANG()作为第二个参数,对列表中的每个pid进行waitpid.


pil*_*row 5

鲍罗丁的答案非常适合儿童终止时的异步收割.

如果,正如您的问题和代码向我建议的那样,您正在寻找所有未完成子项按其终止顺序同步(阻塞)收获,父母可以简单地执行此操作:

use feature qw(say);

...

# Block until all children are finished
while (1) {
  my $child = waitpid(-1, 0);
  last if $child == -1;       # No more outstanding children

  say "Parent: Child $child was reaped - ", scalar localtime, ".";
}

say "All done."
Run Code Online (Sandbox Code Playgroud)