我有一个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',但随后我不得不担心僵尸进程。
是什么原因导致“无子进程”错误,我们该如何解决?
答案 0 :(得分:2)
有人建议将$ SIG {CHLD}从'IGNORE'更改为'DEFAULT',但随后我不得不担心僵尸进程。
这不是真的。
僵尸进程是已经结束但尚未被其父级收割的进程。父母使用wait
(2),waitpid
(2)或类似方法收割其子女。 capture
等待其子项结束,因此不会留下任何僵尸。
实际上,您得到的错误来自waitpid
。 capture
正在等待孩子结束收割并收集其错误代码,但是您指示操作系统在完成工作后立即清理孩子,而waitpid
则没有孩子收割,并且没有错误代码可收集。
要解决此问题,只需在调用local $SIG{CHLD} = 'DEFAULT';
之前放置capture
。