3

这是问题所在:我有一个守护进程,它从客户端获取请求,根据请求执行一个函数(来自某个模块)并向客户端返回一个答案。在 fork() 之后,我关闭了 STDIN、STDOUT 和 STDERR。一个功能是检查 dmesg。为此,我通过 open(DMESG, "/bin/dmesg |") 获得 dmesg 输出。读完后我没有关闭这个 fh,因为我认为它会在函数完成后自动关闭。但这并没有发生,每次调用 dmesg 我都会得到一个僵尸。

关于如何重新初始化 Perl 的 STDIN/STDOUT/STDERR?我发现“关闭 STDOUT 而不是重新打开的问题在于,如果您打开其他文件,它们可能会得到 fd 0,1 或 2 - 阻止您将来重新打开 STDOUT。” by jmanning2k 我认为这与它有关,但我真的不明白。我希望有人能给我解释一下。

我知道我可以避免这个问题,例如通过 qx(); 调用 dmesg; 或者只是关闭 fh 但我想了解僵尸来自哪里。

4

3 回答 3

7

表格

open DMESG, "/bin/dmesg|";

打开管道并将其分配给动态范围的变量DMESG。动态范围的变量实际上“永远”存在于 Perl 中,只要看到 a 就将其保存为必要的local

如果您改为使用表格

open my $dmesg, "/bin/dmesg|";

词法文件句柄变量将$dmesg在范围退出时关闭,假设没有其他理由让它保持活动状态(即它没有被传回或以其他方式存储在全局变量中)。

于 2010-12-15T15:11:36.037 回答
6

open(DMESG, "/bin/dmesg |") 读完后我没有关闭这个 fh,因为我认为它会在函数完成后自动关闭。

为此,句柄必须是词法的,因此它可以正确地超出范围。

open my $dmesg, …
于 2010-12-15T15:10:56.850 回答
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 使用下一个空闲句柄来打开,而旧的句柄仍然打开。

于 2010-12-15T16:24:57.153 回答