Perl:fork(),避免僵尸进程,以及 "No child processes" 错误

Perl: fork(), avoiding zombie processes, and "No child processes" error

我有一个 Perl 应用程序,几年来在 RH 系统上 运行 基本没有问题。在一个地方,我必须 运行 一个可能需要很多分钟才能完成的系统命令,所以我在子进程中执行此操作。整体结构是这样的:

    $SIG{CHLD} = 'IGNORE'; # Ignore dead children, to avoid zombie processes
    my $child = fork();

    if ($child) {    # Parent; return OK
       $self->status_ok();  
    } else {         # Child; run system command
         # do a bunch of data retrieval, etc.
         my $output;
         my @command = # generate system command here
         use IPC::System::Simple 'capture';
         eval { $output = capture(@command); };
         $self->log->error("Error running @command: $@") if $@;
         # success: log $output, carry on
    }

我们最近更改了一些基础架构,尽管不是以我预期的方式对此产生任何影响。 (仍然 运行ning 在 RH 上,仍然使用 nginx 等)但是,现在我们发现几乎 运行ning 这段代码的每个实例都会失败,记录 'Error running {command}: failed to start: "No child processes" at /path/to/code.pl'.

我环顾四周,无法找出正确的解决方案。有人建议将 $SIG{CHLD} 从 'IGNORE' 更改为 'DEFAULT',但我不得不担心僵尸进程。

是什么导致了 "No child processes" 错误,我们该如何解决?

There was a suggestion to change $SIG{CHLD} from 'IGNORE' to 'DEFAULT', but then I have to worry about zombie processes.

这不是真的。

僵尸进程是已经结束但尚未被其 parent 收割的进程。 parent 使用 wait(2)、waitpid(2) 或类似方法获得其 children。 capture 等待它的 child 结束,所以它不会留下任何僵尸。

事实上,您收到的错误来自 waitpidcapture 正在等待 child 结束以获取它并收集其错误代码,但是您指示 OS 在它完成后立即清理 child, waitpid 没有 child 可以收集,也没有错误代码可以收集。

要解决此问题,只需在调用 capture 之前放置 local $SIG{CHLD} = 'DEFAULT';