【问题标题】:Perl: creating zombies through open() without close()Perl:通过 open() 没有 close() 创建僵尸
【发布时间】:2011-05-25 23:30:42
【问题描述】:
问题来了:
我有一个守护进程,它从客户端获取请求,根据请求执行一个函数(来自某个模块)并向客户端返回一个答案。
在 fork() 之后,我关闭了 STDIN、STDOUT 和 STDERR。
一个功能是检查 dmesg。为此,我通过 dmesg 输出
打开(DMESG,“/bin/dmesg |”)。读完后我没有关闭这个 fh,因为我认为它会在函数完成后自动关闭。
但这并没有发生,每次调用 dmesg 都会得到一个僵尸。
在How can I reinitialize Perl's STDIN/STDOUT/STDERR? 我发现“关闭 STDOUT 而不是重新打开的问题是,如果您打开其他文件,它们可能会得到 fd 0,1 或 2 - 阻止您将来重新打开 STDOUT。”通过 jmanning2k
我认为这与它有关,但我真的不明白。希望有人能给我解释一下。
我知道我可以避免这个问题,例如通过 qx() 调用 dmesg;或者干脆关闭 fh 但我想知道僵尸是从哪里来的。
【问题讨论】:
标签:
perl
file-io
filehandle
zombie-process
【解决方案1】:
表格
open DMESG, "/bin/dmesg|";
打开管道并将其分配给动态范围变量DMESG。动态范围的变量实际上“永远”存在于 Perl 中,只要看到 local,就会根据需要保存。
如果您改为使用表单
open my $dmesg, "/bin/dmesg|";
lexical 文件句柄变量$dmesg 将在范围退出时关闭,假设没有其他理由让它保持活动状态(即它没有被传回或以其他方式存储在全局变量中)。
【解决方案2】:
open(DMESG, "/bin/dmesg |")
读完这个fh后我没有关闭它,因为我认为它会在函数完成后自动关闭。
为此,句柄必须是词法的,因此它可以正确地超出范围。
open my $dmesg, …
【解决方案3】:
问题与 Perl 的实现方式有关。这是文件doio.c中函数Perl_do_openn的一段代码:
fd = PerlIO_fileno(IoIFP(io));
if (IoTYPE(io) == IoTYPE_STD) {
/* This is a clone of one of STD* handles */
result = 0;
}
else if (fd >= 0 && fd <= PL_maxsysfd) {
/* This is one of the original STD* handles */
saveifp = IoIFP(io);
saveofp = IoOFP(io);
savetype = IoTYPE(io);
savefd = fd;
result = 0;
}
如果您打开现有的文件句柄,该文件句柄将由open() 关闭并重新打开。从上面的代码可以看出,STD* 句柄不会发生这种情况。所以 Perl 使用下一个空闲句柄来打开,而旧的句柄仍然打开。