您可以将父进程及其子进程放在他们自己的进程组中,并通过向父进程发送信号来杀死整个家庭。
根据问题的性质,您可能愿意kill
离开(McManus 先生!)并忍受由于每次尝试kill
对已经死亡的子进程而导致的失败。
如果父进程除了跟踪孩子什么都不做,waitpid
那么您只需要一个简单的循环。
while ((my $kid = waitpid -1, 0) > 0) {
warn "$0: [$$] reaped $kid\n";
delete $kid{$kid};
}
如果您在父进程中有其他处理,WNOHANG
则将第二个参数中的位设置为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