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;
  }

所以现在我有一个子进程 ID 的哈希值,当父进程发送一个 kill SIGTERM 时我可以杀死它。

但是如果子进程被外部杀死怎么办?父进程知道要启动另一个子进程来弥补丢失的子进程,而新的子进程 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则将第二个参数中的位设置为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 回答