Greg said:
: Greg Bacon wrote:
:
: [snip]
: > my @ready = $sel->can_read(0);
: > foreach my $fh (@ready) {
: [snip]
: > if (my $input = <$fh>) {
:
: Don't do that.
Why not?
The readline (aka <>) operator does the following:
1a/ It scans it's internal buffer for the $/ string, and if
it finds it,
1b/ Removes (and returns) everything in it's buffer up to and
including the $/. Anything after the $/ remains in the buffer.
2/ After we looked for and didn't find $/, it uses the C read()
function to get data from the filedescriptor and adds it to it's
internal buffer.
3/ Go back to step 1.
The can_read method of IO::Select tells us whether or not the file
descriptor has more bytes available... that is, whether or not calling
the C read() function on that fd would block.
Now, let's suppose that the other end of the pipe sends us data faster
than we read it... e.g., suppose that it sends us three lines in the
time it took us to process one.
What happens?
Select's can_read says the pipe is ready to read from, then we call
readline(), which read()s *all* of the bytes that are in the pipe (in
the file descriptor) into the internal byffer. Then, we remove one $/
delimited line from that buffer, leaving two in the buffer. Then, we
call can_read again... and there are no bytes in the pipe! There are
bytes in the buffer, but none to be read from the file descriptor.
Alas, can_read knows nothing of the filehandle's internal buffer, it can
only examine the filedescriptor.
As a result, we won't call <> the extra two times that we should, and
thus those two lines never get read and printed out.
Well, maybe they'll get printed the *next* time a line gets printed to
the other end of the pipe... but that could be quite a long while after
those two lines were sent. It wouldn't be a good thing if we were only
able to read data many minutes after it was sent, would it?
Further, consider if we're doing two-way communication, not just
one-way... suppose the process on the other end of the pipe wants to
read something from us, before it will send anything else to us. We're
in trouble... we can't see what it sent, until it sends us "extra", and
it won't send us extra, until we see and respond to what it sent. This
is known of as deadlock.