如何判断管道打开过程是否已终止?

时间:2011-06-16 20:26:49

标签: perl file-io pipe ipc

假设使用以下代码创建句柄:

use IO::File;

my $fh = IO::File->new;

my $pid = $fh->open('some_long_running_proc |') or die $!;

$fh->autoflush(1);
$fh->blocking(0);

然后用这样的循环读取:

while (some_condition_here) {
    my @lines = $fh->getlines;
    ...
    sleep 1;
}

如果管道另一端的进程终止,我将some_condition_here作为假设返回false?

$fh->eof的测试不起作用,因为该过程仍然可以在不打印任何新行的情况下运行。对$fh->opened的测试似乎没有任何用处。

目前我正在使用$pid =! waitpid($pid, WNOHANG),它似乎适用于符合POSIX标准的环境。这是最好的方法吗?在Windows上怎么样?

4 个答案:

答案 0 :(得分:5)

使用select

use strict;
use warnings;

use IO::Select qw( );

sub process_msg {
    my ($client, $msg) = @_;
    chomp $msg;
    print "$client->{id} said '$msg'\n";
    return 1;  # Return false to close the handle.
}

my $select = IO::Select->new();
my %clients;

for (...) {
    my $fh = ...;
    $clients{fileno($fh)} = {
        id  => '...'
        buf => '',
        # ...
    };

    $select->add($fh);
}

while (my @ready = $select->can_read) {
    for my $fh (@ready) {
        my $client = $clients{ fileno($fh) };
        our $buf; local *buf = \( $client->{buf} );

        my $rv = sysread($fh, $buf, 64*1024, length($buf));
        if (!$rv) {
            if (defined($rv)) {
                print "[$client->{id} ended]\n";
            } else {
                print "[Error reading from $client->{id}: $!]\n";
            }

            print "[Incomplete message received from $client->{id}]\n"
                if length($buf);

            delete $clients{ fileno($fh) };
            $select->remove($fh);
            next;
        }

        while ($buf =~ s/^(.*\n)//) {
            if (!process_msg($client, "$1")) {
                print "[Dropping $client->{id}]\n";
                delete $clients{ fileno($fh) };
                $select->remove($fh);
                last;
            }
        }
    }
}

答案 1 :(得分:2)

等待实际的EOF有什么问题?

while (<$fh>) {
    ...
    sleep 1;
}

你已经设置了非阻塞读取的句柄,所以它应该做正确的事情。实际上,根据你的例子,你甚至不需要设置非阻塞并且可以摆脱睡眠。

some_long_running_proc时还有其他想做的事情吗?如果是这样,select可能就在您的未来。

答案 2 :(得分:2)

有很多选择。

  • readline aka <$fh>将在eof(或错误)上返回false。

  • eof将在eof上返回true。

  • read(块大小> 0)将在eof上返回已定义和零。

  • sysread(块大小> 0)将在eof上返回已定义和零。

您可以使用select或在上述任何操作之前使句柄无阻塞,以便无阻塞地进行检查。

答案 3 :(得分:1)

您可以使用select()来确定是否有任何数据或异常情况,例如关闭。

我个人更喜欢使用IO :: Multiplex,特别是在你从多个不同描述符复用输入的情况下,但在这种情况下可能不适用。