无法读取管道

时间:2017-12-23 05:33:00

标签: perl pipe fork

我不知道我是不是意外地删除了某个地方的错误或突然插入错误,但突然之间我的一些代码停止了工作。由于某些原因,从$ in中没有读取任何行。

use Win32::Job;
use IO::Handle; 

STDOUT->autoflush;

pipe my $in, my $out;

my $job = Win32::Job->new;

sub flush_pipe{
    while (defined(my $line = <$in>)) {
       chomp($line);
       print($line);

    }
}
my $pid = $job->spawn("cmd", "cmd /C \"ipconfig\"",
    {
        stdout=>$out
    }
);
flush_pipe();

编辑: 通过反复试验,我最终发现在冲洗管道之前我必须关闭$ out文件句柄。

1 个答案:

答案 0 :(得分:5)

管道是单向的。它连接的每个进程都可以读或写。

pipe之后你有两个文件句柄,父母和孩子都看到了它们。如果孩子要写和父母要读,就像你的代码一样,那么孩子必须先关闭它不会使用的句柄($in),父母必须关闭其未使用的句柄,{{1 }}。否则你将have deadlocks

模块中的$out启动子进程(或者更确切地说是Windows近似)并将其spawn重定向到管道的写入端STDOUT。< / p>

一些非常基本的代码应该涵盖这个

$out

当您希望打印件立即可供读取器使用时(最多在代码外部缓冲)发送换行符。在执行任何其他操作之前,在每个过程中关闭管道的未使用端。

我现在无法在Windows上编写代码,但在您的代码中,父代必须use strict; use warnings; use feature 'say'; pipe my $in, my $out; my $pid = fork // die "Can't fork: $!"; if ($pid == 0) { # child close $in; print $out "hi "; # can't read this yet (no newline) ... sleep 1; say $out "from child"; # now the other end can read it close $out; exit; } # parent close $out; say while <$in>; close $in; wait; (在close $out之后)。

这里的术语“刷新”可以与编写器中的代码或Perl清除IO缓冲区有关; spawn中的代码只是读取管道。所以我将这个名称更改为flush_pipe()等。