Reading from Many Filehandles Without Blocking

Problem

You want to learn whether input is available to be read, rather than blocking for input as < > does. This is useful when reading from pipes, sockets, devices, and other programs.

Solution

Use select with a timeout value of seconds, if you’re comfortable with manipulating bit-vectors representing file descriptor sets:

$rin = '';
# repeat next line for all filehandles to poll
vec($rin, fileno(FH1), 1) = 1;
vec($rin, fileno(FH2), 1) = 1;
vec($rin, fileno(FH3), 1) = 1;

$nfound = select($rout=$rin, undef, undef, 0);
if ($nfound) {
  # input waiting on one or more of those 3 filehandles
  if (vec($rout,fileno(FH1),1)) { 
      # do something with FH1
  }
  if (vec($rout,fileno(FH2),1)) {
      # do something with FH2
  }
  if (vec($rout,fileno(FH3),1)) {
      # do something with FH3
  }
}

The IO::Select module provides an abstraction to hide the bit-vector operations:

use IO::Select;

$select = IO::Select->new();
# repeat next line for all filehandles to poll
$select->add(*FILEHANDLE);
if (@ready = $select->can_read(0)) {
    # input waiting on the filehandles in @ready
}

Discussion

The select function is really two functions in one. If you call it with one argument, you change the current default output filehandle (see Section 7.12). If you call it with four arguments, it tells you which filehandles have input waiting or are ready to receive output. This recipe only deals with four-argument select.

The first three arguments to select are strings containing bit-vectors. Each ...

Get Perl Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.