问题在于: 我有一个守护进程,它从客户端获取请求,由于请求而执行一个函数(来自某个模块)并向客户端返回一个答案。 在fork()之后我关闭了STDIN,STDOUT和STDERR。 一个功能是检查dmesg。为此,我得到了dmesg输出 打开(DMESG,“/ bin / dmesg |”)。读完之后我没有关闭这个fh,因为我认为它会在函数完成后自动关闭。 但这不会发生,每次调用dmesg都会得到一个僵尸。
On How can I reinitialize Perl's STDIN/STDOUT/STDERR?我发现“关闭STDOUT而不是重新打开的问题是,如果你打开其他文件,它们可能会得到fd 0,1或2 - 阻止你将来重新打开STDOUT。”通过jmanning2k 而且我认为它与它有关,但我并没有真正理解它。我希望有人可以向我解释。
我知道我可以避免这个问题,例如通过qx()调用dmesg;或者只是关闭fh,但我想了解僵尸的来源。
答案 0 :(得分:7)
表格
open DMESG, "/bin/dmesg|";
打开管道并将其分配给动态作用域变量DMESG
。动态范围的变量实际上在Perl中“永久”存在,只要看到local
,就会根据需要进行保存。
如果您改为使用表格
open my $dmesg, "/bin/dmesg|";
词汇文件句柄变量$dmesg
将在范围退出时关闭,假设没有其他原因使其保持活动状态(即它没有被传回或以其他方式存储在全局变量中)。
答案 1 :(得分:6)
open(DMESG, "/bin/dmesg |")
在阅读之后我不会关闭这个fh,因为我认为它会在函数完成后自动关闭。
为了使其工作,句柄必须是词法的,因此它可以正确地落在范围之外。
open my $dmesg, …
答案 2 :(得分:1)
问题与Perl的实现方式有关。以下是文件Perl_do_openn
中函数doio.c
的一段代码:
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将下一个空闲句柄打开,旧版本保持打开状态。