linux - 如何跟踪子进程

标签 linux perl fork

所以我的程序生成了一些子进程来响应某些事件,我正在做类似这样的事情来跟踪并在程序退出时杀死它们(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
   }
}

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

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

编辑:为了更好地跟踪 child ,可以按如下方式扩展代码(但是它也会遇到完全相同的竞争条件,所以这就是我一开始没有完整编写它的原因):

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 的内容也可能无法反射(reflect)实际活跃的 child 。

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

最佳答案

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

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

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

关于linux - 如何跟踪子进程,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25192995/

相关文章:

c - 中止功能如何永不返回?

linux - ls命令用于搜索当前目录中的特定文件

linux - 如何与 parent 沟通 child 关闭了管道的写入端?

Perl,延迟评估字符串

c - 在消息末尾获取不需要的字符

c - 进程组中的进程是否应该在 Unix/Linux 中与其父进程一起终止?

c - 远程文件系统上的 open() 系统调用会阻塞吗?

c++ - 在 Linux 上使用 GCC 交叉编译适用于 Windows 的 Qt 应用程序

perl - 如果不存在,则在Perl中为日志文件创建目录

multithreading - 在Perl中,当运行使用open fork 的另一个子进程时,我无法加入线程