首页 文章

如何在perl的父进程中获取死亡的子进程的PID?

提问于
浏览
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以将其从哈希中删除所以我以后不要试图杀死它?

我可以设置 $SIG{CHLD} 但是我没有看到如何让子PID从哈希中删除它 .

2 回答

  • 0

    您可以将父项及其子项放在自己的进程组中,并通过向父项发送信号来终止整个系列 .

    根据您的问题的性质,您可能愿意离开(麦克马纳斯先生!),并且因为每次尝试 kill 对已经死亡的子进程感到失败 .

    如果父进程除了跟踪孩子之外什么都不做,那么您只需要一个简单的循环 .

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

    现在,上面的循环读取了ob告 .

    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] forked 7976
    ./waitpid-demo: [7976] sleeping...
    ./waitpid-demo: [1948] forked 7244
    ./waitpid-demo: [7244] sleeping...
    ./waitpid-demo: [1948] forked 4776
    ./waitpid-demo: [4776] sleeping...
    ./waitpid-demo: [1948] forked 4304
    ./waitpid-demo: [4304] sleeping...
    ./waitpid-demo: [1948] forked 7908
    ./waitpid-demo: [7908] sleeping...
    ./waitpid-demo: [5144] The killer awoke before dawn.
    ./waitpid-demo: [5144] killing 7908...
    ./waitpid-demo: [1948] reaped 7908
    ./waitpid-demo: [5144] killing 7976...
    ./waitpid-demo: [1948] reaped 7976
    ./waitpid-demo: [5144] killing 4776...
    ./waitpid-demo: [1948] reaped 4776
    ./waitpid-demo: [5144] killing 4304...
    ./waitpid-demo: [1948] reaped 4304
    ./waitpid-demo: [5144] killing 7244...
    ./waitpid-demo: [1948] reaped 7244
    ./waitpid-demo: [1948] reaped 5144
    
  • 4

    如果唯一的问题是"remove it from the hash so I don't try and kill it later",您可以尝试以下方法:

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

相关问题