1

私はproc::queueを使用して子プロセスの山を管理しており、次のようにそれらを起動します。

if(Proc::Queue::running_now() < $kids)
  {
    logger("Starting another server process...");
    my $newprocessid = Proc::Queue::run_back(\&serverprocess);
    logger("New child process id: $newprocessid");
    $childprocessids{$newprocessid} = 1;
  }

これで、親プロセスにkillSIGTERMが送信されたときにkillできる子プロセスIDのハッシュができました。

しかし、子プロセスが外部で強制終了された場合はどうなりますか?親プロセスは、失われた子を補うために別の子を起動することを知っており、新しい子PIDは最終的に私のハッシュになりますが、親はどのようにして、ハッシュからそれを削除するために死亡した子のPIDを見つけることができますか?後で殺そうとしないのですか?

設定することはできます$SIG{CHLD}が、子PIDを取得してハッシュから削除する方法がわかりません。

4

2 に答える 2

4

親とその子を独自のプロセスグループに配置し、親に信号を送信して家族全員を殺すことができます。

問題の性質によっては、kill(McManus氏!)離れて、killすでに死んでいる子プロセスで試行されるたびに失敗に耐えることができる場合があります。

親プロセスが子を追跡する以外に何もしない場合、waitpid必要なのは単純なループだけです。

while ((my $kid = waitpid -1, 0) > 0) {
  warn "$0: [$$] reaped $kid\n";
  delete $kid{$kid};
}

親プロセスに他の処理がある場合はWNOHANG、2番目の引数のビットを設定しwaitpidて、システムコールにブロックしないように指示します。これにより、ゾンビの子を定期的に刈り取り、他の処理に戻ることができます。

デモンストレーションの目的で、眠い子供たちをたくさん立ち上げたとしましょう。

#! /usr/bin/env perl

use strict;
use warnings;

use 5.10.0;  # for defined-or

my %kid;

for (1 .. 5) {
  my $pid = fork // die "$0: fork: $!";  # / fix SO hilighting
  if ($pid == 0) {
    warn "$0: [$$] sleeping...\n";
    sleep 10_000;
    exit 0;
  }
  else {
    $kid{$pid} = 1;
    warn "$0: [$$] forked $pid\n";
  }
}

次に、外部からの殺害をシミュレートするために、別の子をフォークして、残りの兄弟をランダムにピックします。

my $pid = fork // die "$0: fork: $!";
if ($pid == 0) {
  warn "$0: [$$] The killer awoke before dawn.\n";
  while (keys %kid) {
    my $pid = (keys %kid)[rand keys %kid];
    warn "$0: [$$] killing $pid...\n";
    kill TERM => $pid or warn "$0: [$$] kill $pid: $!";
    delete $kid{$pid};
    sleep 1;
  }
  exit 0;
}

これで、上からのループが死亡記事を読み取ります。

while ((my $kid = waitpid -1, 0) > 0) {
  warn "$0: [$$] reaped $kid\n";
  delete $kid{$kid};
}

誰も生きていないことを再確認してください。

if (keys %kid) {
  my $es = keys %kid == 1 ? "" : "es";
  die "$0: unkilled process$es:\n",
      map "  - $_\n", keys %kid;
}

出力:

./waitpid-demo:[1948]フォーク7976
./waitpid-demo:[7976]スリープ中...
./waitpid-demo:[1948]フォーク7244
./waitpid-demo:[7244]スリープ中...
./waitpid-demo:[1948]フォーク4776
./waitpid-demo:[4776]スリープ中...
./waitpid-demo:[1948]フォーク4304
./waitpid-demo:[4304]スリープ中...
./waitpid-demo:[1948]フォーク7908
./waitpid-demo:[7908]スリープ中...
./waitpid-demo:[5144]キラーは夜明け前に目が覚めた。
./waitpid-demo:[5144]7908を殺す...
./waitpid-demo:[1948]は7908を刈り取りました
./waitpid-demo:[5144]7976を殺す...
./waitpid-demo:[1948]は7976を刈り取りました
./waitpid-demo:[5144]4776を殺す..。
./waitpid-demo:[1948]は4776を刈り取りました
./waitpid-demo:[5144]4304を殺す...
./waitpid-demo:[1948]は4304を刈り取りました
./waitpid-demo:[5144]7244を殺す..。
./waitpid-demo:[1948]刈り取られた7244
./waitpid-demo:[1948]は5144を刈り取りました
于 2012-05-14T13:38:29.710 に答える
0

唯一の問題が「ハッシュから削除して、後で殺そうとしないようにする」である場合は、次のことを試すことができます。

# probably you should put this code in a loop for all your process IDs
$alive = kill 0, $childprocessids{$processId};

if ( $alive ) {
    # process is still alive, do whatever you want with it
}
else {
    # process is dead, probably killed externally
    # do whatever you need for this scenario or just delete your hash key
}
于 2012-05-14T13:55:25.323 に答える