Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

I have two programs, call them "A" and "B." Program B produces output periodically, and program A opens a pipe for reading to catch the output. The problem is that if there's no output to be read at that particular moment, the call to read hangs until there is, all the while program A is completely unresponsive. What's the simplest, most efficient way to tell whether or not an opened pipe has data to be read, before calling read() or sysread() on it?
  • Comment on How to tell if a pipe opened for reading has data to be read

Replies are listed 'Best First'.
Re: How to tell if a pipe opened for reading has data to be read
by superfrink (Curate) on Mar 30, 2007 at 03:11 UTC

      Doesn't seem to be working. This code prints select()'ed, then blocks for 5 seconds and prints [Piped output] instead of printing nothing yet immediately and exiting.

      #!/usr/bin/perl -w use strict; use Symbol; my $sym = gensym; open($sym, "perl -e 'sleep(5); print qq!Piped output!;' |") or die $!; my ($rin, $rout); $rin = ''; vec($rin, fileno $sym, 1) = 1; my $changed = select($rout = $rin, undef, undef, 0); print "select()'ed\n"; if ($changed && vec($rout, fileno $sym, 1) == 1) { my $buf; sysread($sym, $buf, 4096); print "[$buf]"; } else { print "nothing yet"; }
        You're suffering from buffering - that program acutally print()s "nothing yet" immediately but you won't see it till the program ends because your output is buffered. try this:
        #!/usr/bin/perl -w use strict; use Symbol; $|=1; # turn off buffering my $sym = gensym; open($sym, "perl -e 'sleep(5); print qq!Piped output!;' |") or die $!; my ($rin, $rout); $rin = ''; vec($rin, fileno $sym, 1) = 1; my $changed = select($rout = $rin, undef, undef, 0); print "select()'ed: changed=$changed\n"; if ($changed && vec($rout, fileno $sym, 1) == 1) { my $buf; sysread($sym, $buf, 4096); print "[$buf]\n"; } else { print "nothing yet\n"; }
Re: How to tell if a pipe opened for reading has data to be read
by saintly (Scribe) on Mar 30, 2007 at 05:51 UTC
    Perhaps you might benefit from having a look at the answers from the last time this question was asked:

    - Non blocking read on a filehandle

    One example that was reported to work was the one about halfway down using Fcntl. Only worked on UNIX though, which doesn't seem like it will be a hindrance for you.

    Although setting select's timeout to 0 doesn't work, you could set a minimal timeout like 0.01 (1 ms) which might work in your current implementation scheme, but is still inelegant.
      Hm. Why does setting select's timeout to 0 not work? It should work, at least in POSIX-compatible implementations.
        I was hoping that Perl would turn an 'undef' for $timeout into a NULL pointer and '0' for $timeout into a struct timeval with a 0 value, but I hadn't tested it. One of the comments in the earlier thread Re: Re: Non blocking read on a filehandle indicated it wasn't working then (back in 2001).
Re: How to tell if a pipe opened for reading has data to be read
by zentara (Cardinal) on Mar 30, 2007 at 13:17 UTC
    Look at "perldoc -q filehandle" and search for the word ioctl. There is a low-level method to tell how many characters are waiting in a pipe. I tried to use it on "bc" in IPC3 buffer limit problem

    I'm not really a human, but I play one on earth. Cogito ergo sum a bum