perl - Perl:fork(),避免僵尸进程和“无子进程”错误
问题描述
我有一个 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 等)但是,现在我们发现运行此代码的几乎每个实例都失败了,记录 'Error running {command}: failed to start: "No child processes" at /path/to /code.pl'。
我环顾四周,无法弄清楚正确的解决方案是什么。有人建议$SIG{CHLD}
从“忽略”更改为“默认”,但我不得不担心僵尸进程。
是什么导致“无子进程”错误,我们如何解决这个问题?
解决方案
有人建议将 $SIG{CHLD} 从“IGNORE”更改为“DEFAULT”,但我不得不担心僵尸进程。
这不是真的。
僵尸进程是一个已经结束但尚未被其父进程收割的进程。父母使用wait
(2)、waitpid
(2) 或类似的方法来收获其孩子。capture
等待它的孩子结束,所以它不会留下任何僵尸。
实际上,您得到的错误来自waitpid
. capture
正在等待孩子结束收割并收集其错误代码,但是您指示操作系统在完成后立即清理孩子,waitpid
没有孩子可以收割,也没有错误代码可以收集。
要解决此问题,只需local $SIG{CHLD} = 'DEFAULT';
在调用capture
.
推荐阅读
- unreal-engine4 - 如何创建测试应用程序以在 UE4 中创建许多屏幕截图?
- security - 防止微服务中的特权升级
- python - 从摄氏度到华氏度的温度转换,显示从给定开始到结束温度的转换
- ipfs - 如何让 libp2p 集合服务器运行?
- c++ - 删除 QSharedPointer 指向的 QObject
- openshift - 在 OKD 中添加新用户,但 htpasswd 不起作用
- r - 创建一个新向量并将其组件基于另一个向量的先前迭代?
- php - 将一个表单的数据从一个页面和另一个表单的第二页一起传递到电子邮件
- fedora - 无法使用 rpm 在 Fedora 28 中安装 Opera
- python - 如何用 BeautifulSoup 抓取页面?页面源与检查元素不匹配