How do you tell if a pipe opened process has terminated?
Assuming a handle created with the following code:
use IO::File;
my $fh = IO::File->new;
my $pid = $fh->open('some_long_running_proc |') or die $!;
$fh->autoflush(1);
$fh->blocking(0);
and then read with a loop like this:
while (some_condition_here) {
my @lines = $fh->getlines;
...
sleep 1;
}
What do I put as some_condition_here
that will return false if the process on the other end of the pipe has terminated?
Testing for $fh->eof
will not work since the process could still be running without printing any new lines. Testing for $fh->opened
doesn't seem to do anything useful.
Currently I am using $pid =! waitpid($pid, WNOHANG)
which seems to work in POSIX compliant environments. 开发者_如何学C Is this the best way? What about on Windows?
On using 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;
}
}
}
}
What's wrong with waiting for an actual EOF?
while (<$fh>) {
...
sleep 1;
}
You've set the handle for non-blocking reads, so it should just do the right thing. Indeed, given your example, you don't even need to set non-blocking and can get rid of the sleep.
Are there other things that you want to do while waiting on some_long_running_proc
? If so, select
is probably in your future.
There a number of options.
readline
aka<$fh>
will return false on eof (or error).eof
will return true on eof.read
(with block size > 0) will return defined and zero on eof.sysread
(with block size > 0) will return defined and zero on eof.
You can use select
or make the handle non-blocking before any of the above to check without blocking.
You use select() to ascertain whether there is any data, or an exceptional condition such as a close.
Personally I prefer to use IO::Multiplex, especially where you're multiplexing input from several different descriptors, but that may not apply in this case.
精彩评论