【问题标题】:How to keep track of child processes如何跟踪子进程
【发布时间】:2014-08-07 22:00:44
【问题描述】:

所以我的程序生成了许多子进程来响应某些事件,我正在做类似的事情来跟踪并在程序退出时杀死它们(Perl 语法):

my %children = ();

# this will be called upon exit
sub kill_children {
  kill 'INT' => keys %children;
  exit;
}

# main code

while(1) {

   ...
   my $child = fork();

   if ($child > 0) {
     $children{$child} = 1;
   } elsif ($child == 0) {
     # do child work ...
     exit();
   } else {
     # handle the error
   }
}

所以思路如上。但是,那里有一个明显的竞争条件,因为给定的孩子可以在父亲有机会运行并将其 pid 记录在 %children 哈希中之前开始和终止。所以父亲最终可能会认为给定的 pid 属于一个活跃的孩子,即使这个孩子已经终止。

有没有办法以安全的方式完成我想要完成的事情?

编辑:为了更好地跟踪孩子,可以将代码扩展如下(但它也遭受完全相同的竞争条件,所以这就是为什么我一开始没有完全编写它的原因):

my %children = ();

sub reap {
  my $child;
  while (($child = waitpid(-1, WNOHANG)) > 0) {
    #print "collecting dead child $child\n";
    delete $children{$child};
  }
}

$SIG{CHLD} = \&reap;

# this will be called upon exit
sub kill_children {
  local $SIG{CHLD} = 'IGNORE';
  kill 'INT' => keys %children;
  exit;
}

# main code

while(1) {

   ...
   my $child = fork();

   if ($child > 0) {
     $children{$child} = 1;
   } elsif ($child == 0) {
     # do child work ...
     exit();
   } else {
     # handle the error
   }
}

即使在这种情况下,%children 的内容也可能无法反映实际活跃的孩子。

编辑 2: 我找到了this question,这几乎是同一个问题。我喜欢那里建议的解决方案。

【问题讨论】:

  • 这与 Perl 无关。几乎任何语言都会存在同样的问题。
  • 您的示例在 Perl 中,它在没有它的平台上模拟 fork。这可能会对答案产生影响。
  • 我可以用 C 编写完全相同的示例,但问题仍然有效。无论如何,我是在 Linux 下运行的。

标签: linux perl fork


【解决方案1】:

在 UNIX 上,这不是竞争条件。这是处理fork() 的标准方式。当子进程退出时,其状态变为“终止”;它变成了zombie。在父进程调用wait 函数之一之前,它仍然在进程表中有一个条目。只有在那之后才真正删除了死进程。

即使父级设置自己忽略 SIGCHLD,它仍然不符合竞态条件;父母只会有一个不再有效的PID。在这种情况下,wait() 将返回 ECHILD。 但是设置 SIGCHLD 会释放子进程的 PID,可能导致父进程试图杀死一个不是子进程的进程。

在没有fork 调用的Windows 上,它是通过在perl 进程中创建一个线程来模拟的。见perlfork。我对 Windows 的了解不够多,无法判断这是否会导致竞争条件,但我怀疑不会。

【讨论】:

  • 不一定:SIGCHLD 的处理程序可以设置为 SIG_IGN 并且孩子永远不会变成僵尸,而父亲不需要调用 wait()。
  • 或者你可以使用双叉防止僵尸。
  • @homer5439 如果将父进程设置为忽略 SIGCHLD,为什么还要让它保留子进程 PID 列表?
  • 因为我想在程序结束时杀死它们并清理它们。我将编辑问题以重新表述问题并提供更多详细信息。
  • @homer5439 这就是wait 系统调用的用途。
猜你喜欢
  • 2010-12-24
  • 2016-04-27
  • 2011-05-02
  • 2011-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-05-06
相关资源
最近更新 更多