pipe - non blocking read? (fork/Win32)

S

Stuart Moore

Hi, I'm using windows, I want to create a new process using fork (in
Activestate's Perl 5.6.x for some x) and communicate between the parent
and child using pipes. But I'd like the parent to be able to check if
there was anything waiting for it in the pipe, and if not, come back and
check later.

Is this possible? If not any suggestions on what I can do?

Stuart
 
S

Stuart Moore

: Hi, I'm using windows, I want to create a new process using fork (in
: Activestate's Perl 5.6.x for some x) and communicate between the parent
: and child using pipes. But I'd like the parent to be able to check if
: there was anything waiting for it in the pipe, and if not, come back and
: check later.
:
: Is this possible? If not any suggestions on what I can do?

Is there a reason you'd prefer pipes to, say, sockets?

Um, no. Can Socekts do that? In which case how? A brief trawl through the
documentation gave me nothing.

Thank you very much
Stuart
 
G

Greg Bacon

: On Wed, 2 Jul 2003, Greg Bacon wrote:
:
: > Is there a reason you'd prefer pipes to, say, sockets?
:
: Um, no. Can Socekts do that? In which case how? A brief trawl through
: the documentation gave me nothing.

At the bottom of the IO::Select manpage is a socket server. Here's
an adaptation of that:

#! /usr/local/bin/perl

use warnings;
use strict;

use IO::Select;
use IO::Socket;

sub child {
my $port = shift;

my $s = IO::Socket::INET->new(PeerAddr => "localhost:$port");
die "$0: failed to create socket in child" unless $s;

for (1 .. 5) {
sleep rand 10;

print $s "message #$_\n";
}
}

sub do_something_else {
print "parent: Doing something else...\n";
sleep rand 5;
print "parent: Done.\n";
}

sub check_sockets {
my $lsn = shift;
my $sel = shift;

my @ready = $sel->can_read(0);
foreach my $fh (@ready) {
if ($fh == $lsn) {
# Create a new socket
my $new = $lsn->accept;
$sel->add($new);
}
else {
# Process socket
my $fd = fileno $fh;

if (my $input = <$fh>) {
chomp $input;
print "parent: fd $fd: [$input]\n";
}
else {
$sel->remove($fh);
$fh->close;

$lsn->close;
}
}
}
}

## main
my $port = 8080;
my $lsn = new IO::Socket::INET(Listen => 1, LocalPort => $port);
my $sel = new IO::Select($lsn);

my $pid = fork;
die "$0: fork: $!" unless defined $pid;

unless ($pid) {
child $port;
exit 0;
}

while ($lsn->opened) {
check_sockets $lsn, $sel;

do_something_else;
}

Hope this helps,
Greg
 
G

Greg Bacon

: 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?

Greg
 
B

Benjamin Goldberg

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.
 
B

Bryan Castillo

: 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?

perldoc -f select

<snip>

WARNING: One should not attempt to mix buffered I/O (like "read"
or <FH>) with "select", except as permitted by POSIX, and even
then only on POSIX systems. You have to use "sysread" instead.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads


Members online

Forum statistics

Threads
473,767
Messages
2,569,572
Members
45,046
Latest member
Gavizuho

Latest Threads

Top