11

一連の子を生成するスクリプトがあります。親は、各子が終了するまで待つ必要があります。

私のスクリプトは、次の 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";

上で提供したコードと同様に、それぞれの子が完了するまでに異なる時間がかかる場合があります。

問題は、子の PID をループして子を取得しようとすると、その最後のforeachブロックで、親が作成された順序で子を待機することです。

明らかに、子供たちは生成された順序で終了しないため、たまたま早期に終了する子供向けのゾンビプロセスがたくさん残っています。

私の実際のコードでは、これらの子プロセスが他のプロセスより数日早く終了する可能性があり、ゾンビ プロセスの数が数百単位で増加する可能性があります。

一連の子供たちを刈り取るためのより良い方法はありますか?

4

4 に答える 4

6

pid に「-1」を使用するか、wait() 関数を使用して子プロセスを待機します。取得した pid が返されるので、必要に応じてリストと照合できます。それが受け入れられない場合は、2 番目の引数として POSIX::WNOHANG() を使用して、リスト内の各 pid に対して定期的に waitpid を実行します。

于 2012-06-06T23:16:46.717 に答える
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."
于 2012-06-07T04:52:07.207 に答える
1

次のようなループを使用して子を待機しないでください。

while (1) {
    my $child = waitpid(-1, POSIX::WNOHANG);
    last if $child == -1;
    print "Parent: Child $child was reaped\n";
}

親プロセスは、子プロセスが終了するのを待っている間、特に長時間実行できる場合に、100% の CPU を消費します。少なくとも睡眠を追加してください(悪い考えです-彼らが早く死ぬとき、親は待っています)。

快適さのために、常に TERM/INT/ppid のブロッキング待機 + カウントを使用してください!:

my $loop = 1;
$SIG{CHLD} = 'DEFAULT';  # turn off auto reaper
$SIG{INT} = $SIG{TERM} = sub {$loop = 0; kill -15 => @children_pids};
while ($loop && getppid() != 1) {
    my $child = waitpid(-1, 0);
    last if $child == -1;
    print "Parent: Child $child was reaped\n";
}

このブロッキング待機は、親プロセスが getppid() 呼び出しのように他のことも行う必要がある場合はもちろん不可能です;-)。そのためには、socketpair() を使用して、ブロッキング呼び出しを行う select() に入れることができます。ループチェックでさえ、その恩恵を受けることができます。

于 2012-06-09T09:52:54.373 に答える