Perl:fork(),避免出现僵尸进程,并出现“无子进程”错误

时间:2019-08-27 17:49:48

标签: perl ipc

我有一个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
    }

我们最近更改了一些基础架构,尽管没有以我预期的方式对其产生任何影响。 (仍然在RH上运行,仍然使用nginx等。)但是,现在我们发现几乎所有运行此代码的实例都失败,记录为“运行{command}时出错:无法启动:/ path / to的“无子进程” /code.pl'。

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

是什么原因导致“无子进程”错误,我们该如何解决?

1 个答案:

答案 0 :(得分:2)

  

有人建议将$ SIG {CHLD}从'IGNORE'更改为'DEFAULT',但随后我不得不担心僵尸进程。

这不是真的。

僵尸进程是已经结束但尚未被其父级收割的进程。父母使用wait(2),waitpid(2)或类似方法收割其子女。 capture等待其子项结束,因此不会留下任何僵尸。

实际上,您得到的错误来自waitpidcapture正在等待孩子结束收割并收集其错误代码,但是您指示操作系统在完成工作后立即清理孩子,而waitpid则没有孩子收割,并且没有错误代码可收集。

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