2012-06-06 21 views
10

私は、一連の子を生成するスクリプトを持っています。親は、各子供が終了するのを待つ必要があります。私のスクリプトは、以下のperlスクリプトに似行い子プロセスを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"; 

、それぞれの子が完了するの異なる時間がかかることがあります。

問題は、最後のforeachブロックで、子PIDをループすることによって子どもを刈り取ろうとするときです。親は、作成された順番で子を待ちます。

明らかに、子供たちは産卵された順番で終わらないので、私は早期に終わる子供のためのゾンビプロセスが残っています。

私の実際のコードでは、これらの子どもたちはお互いに前に終わることがあり、周りに浮かんでいるゾンビプロセスの数は何百にも増えます。

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

答えて

12

は、あなたは彼らが完了し、自動的にすべての子を享受する

$SIG{CHLD} = 'IGNORE'; 

をだけを設定することができます。

あなたが完了した子供が通知される必要性を行う場合は、シグナルハンドラは、すべての可能なプロセス

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"; 
    } 
}; 
+1

通知する主な理由:成功したかどうかを確認する。 – ikegami

+0

こんにちはボロディン、[構文::機能::ループ](http://search.cpan.org/perldoc?Syntax::Feature::Loop)をチェックしてください – ikegami

+0

@ikegami:はい私は時々それを使用します。私はたいてい 'while(1)'、 'while()'と '{... redo; } '。本当に満足できるものはありません。 – Borodin

6

pidに "-1"を使用するか、wait()関数を使用して子プロセスを待つようにします。刈り取られたpidが返されるので、必要に応じてあなたのリストに対してチェックすることができます。それが受け入れられない場合は、POSIX :: WNOHANG()を第2引数としてリスト内の各pidを周期的にwaitpidします。あなたの親プロセスがその子供の完了状態を意識する必要がない場合は

5

Borodin's answerを享受するために設定する必要が彼らのように子供の非同期刈り取りのために完全に罰金です終了する。

あなたの質問およびコードは私に提案として、あなたは彼らがを終了した順序ですべての未処理の子どもの刈り取り(ブロッキング)同期を探している、場合、親は単にこれを行うことができます:

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." 
1

は、子どもたちを待つために、このようなループを使用しないでください:

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

死ぬために子プロセスを待っている間に、親プロセスがCPUを100%消費します - E特別に彼らは長い間実行することができます。少なくとも睡眠を加える(悪いアイデア - 早く死ぬと親が待っている)。

必ずブロッキング待ち時間+は、nice値のために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()に入れることができます。ループチェックでさえそれから利益を得ることができます。

+0

これは永遠に繰り返すべきではありません、それは '最後のif'行がすることです。子どもが死亡していない場合、ループを終了します。 –

+0

これは永遠のループではなく、ループ中に使用された100%のCPUサイクルです。 200プロセスが終了するまでに10分かかる場合は、1プロセスで100%CPUサイクルを10分間無駄にしますが、ブロックすると基本的には無くなります。 – CowboyTim

関連する問題