親とその子を独自のプロセスグループに配置し、親に信号を送信して家族全員を殺すことができます。
問題の性質によっては、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を刈り取りました