Perl:当子/管道的文件句柄被别名时,关闭子进程失败
Posted
技术标签:
【中文标题】Perl:当子/管道的文件句柄被别名时,关闭子进程失败【英文标题】:Perl: closing child process fails when file handle to child/pipe is aliased 【发布时间】:2020-07-29 22:54:32 【问题描述】:我已经阅读了有关 open、close 和 IPC 的所有 perl 文档,并阅读了许多相关的论坛主题,但仍然无法弄清楚我做错了什么。首先,我创建了这个简单的分叉进程来证明我正确地进行了打开处理:
#!/usr/bin/perl
use IO::Handle;
my $pid = open(CHILD, "|-");
if ($pid == 0)
# child:
while (<STDIN>) # keeps reading until parent closes it's end of the pipe
chomp $_;
print "child: $_\n";
else
# parent:
for my $line (1..3)
print CHILD "$line\n";
my $success = close CHILD;
print "parent: success: $success, \$!: $!, \$?: $?\n";
正如预期的那样,输出是:
child: 1
child: 2
child: 3
parent: success: 1, $!: Illegal seek, $?: 0
成功值为真;所以我只是忽略了“非法寻求”,因为它不相关,据说。但是,当我将 STDOUT 别名为管道(以避免需要显式打印到 CHILD)然后将 STDOUT 恢复为其原始值时,如下所示,关闭的 CHILD 不再起作用(即使 STDOUT 不再指向它) :
#!/usr/bin/perl
use IO::Handle;
my $pid = open(CHILD, "|-");
if ($pid == 0)
# child:
while (<STDIN>) # keeps reading until parent closes it's end of the pipe
chomp $_;
print "child: $_\n";
else
# parent:
open(ORIG_STDOUT, ">&STDOUT") or die "Unable to dup STDOUT: $!";
open(STDOUT, ">&=CHILD") or die "Unable to alias CHILD: $!";
for my $line (1..3)
print "$line\n";
open(STDOUT, ">&=ORIG_STDOUT") or die "Unable to alias ORIG_STDOUT: $!";
my $success = close CHILD;
print "parent: success: $success, \$!: $!, \$?: $?\n";
输出是这样的:
child: 1
child: 2
child: 3
parent: success: , $!: Illegal seek, $?: -1
success 值不再为 true,这意味着关闭管道时出错,或者 CHILD 返回了一个非零值。 $ 的 -1 值?表示等待系统调用由于某种原因失败,我不确定“非法搜索”是什么意思,但事实是 $!不为零,进一步表明不仅仅是 CHILD 进程返回一个非零代码使关闭 CHILD 返回错误,而是关闭过程中存在某种错误。我在这里错过了什么?
【问题讨论】:
CHILD 是特殊的,因为它还充当孩子的句柄。使用>&=
似乎把事情搞砸了。复制句柄 (>&
) 而不是复制其 fd (>&=
) 作品
【参考方案1】:
至少有两个问题。首先,您对 open
的调用实际上在两个程序中都失败了,或者更确切地说,如果您在第一次调用之后附加了 check 子句,它就会失败。
#!/usr/bin/perl
use IO::Handle;
my $pid = open(CHILD, "|-") or die("A descriptive message");
程序在执行时立即崩溃。然而,由于开放模式参数中的管道意味着对fork
的调用,这意味着应该有两个独立的进程相当于总输出。可以理解的是,您假设调用成功,因为在那之后的代码正在执行。
然而,对open
的调用失败的原因是多方面的,而且很有趣。你传入了一个无效的文件描述符,但是如果子进程可以存活足够长的时间来尝试复制文件描述符,就会发生一些非常有趣的事情。在对open
的调用中使用">&="
而不是简单的">&"
将对内核的底层调用从dup
更改为fdopen
;第一个返回一个文件descriptor,第二个返回一个文件handle。 (在 C 中:int
与 FILE*
)
TL;DR:您没有复制文件描述符,因为您说您不想复制文件描述符,并且查找错误是尝试读取 1 + n
字节超过 0
的逻辑结果您从调用open
收到的空句柄的总字节数。
【讨论】:
以上是关于Perl:当子/管道的文件句柄被别名时,关闭子进程失败的主要内容,如果未能解决你的问题,请参考以下文章