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

A co-worker of mine is trying to write a simple unidirectional named pipe script where the parent process will assign tasks to several child processes. The idea was to have each child read only one line from the pipe, which he tells me can be done in C. But apparently in Perl the first child to connect is reading the entire buffer.

Since he's out today I thought I would try my very inexperienced hand at this. The closest I could get is below, which is based on an exmaple in Network Programming with Perl. Since I'm not really familair with this type of programming I used pipe() instead of named pipes.

To reitierate, the question is is there a way to have each child process actually read just one line from the pipe? Any pointers (and other terrible C puns) are appreciated!!

#!/usr/local/bin/perl use strict; use warnings; sub child { my( $child ) = @_; if( fork == 0 ) { # Child close WRITER; select STDOUT; $| = 1; select READER; $| = 1; while( 1 ) { my $line = <READER>; print STDOUT "$child: $line"; sleep 1; } } return; } pipe( READER, WRITER ) or die "Can't open pipe: $!"; # Create children child( 'a' ); child( 'b' ); child( 'c' ); child( 'd' ); child( 'e' ); # Parent close READER; select WRITER; $| = 1; my $str = ""; foreach ( 0..50 ) { $str .= "$_\n"; } while( 1 ) { print WRITER $str; }

Update: Put the sleep 1 in and merged some of the child() lines.

Replies are listed 'Best First'.
Re: Pipes: Is it possible for a child to just read one line? (records)
by tye (Sage) on Oct 18, 2006 at 22:56 UTC

    There are systems with record-based pipes (VMS in particular and I think Win32 has something like that for pipes) where something like this could work but only if you write each record with a separate call to write(1); such as using $| like you did but doing print WRITER "$_\n" and moving your foreach to inside of your while loop.

    For byte-stream pipes, this could work if you used fixed-length records (and unbuffered I/O on both sides).

    If you want to use variable-length "records" portably, then you'll need to use a more complicated approach. You can have the dispatcher write the record length (in a fixed number of bytes) and then write the data for that record. Each client can lock a semaphore, read the fixed-length data, pull the record length out of it, read the variable-length record, then unlock the semaphore.

    - tye        

Re: Pipes: Is it possible for a child to just read one line?
by ikegami (Patriarch) on Oct 18, 2006 at 22:32 UTC
    <FH> and read are buffered reads. sysread doesn't buffer, but you'll probably have to read it a byte at a time to avoid reading too much. ( I'm concerned with the possibility of two children reading from the pipe at the same time. )
      Thanks! I think you are right -- I noticed that when I put the sleep in child() that more than one child process was reading the same line.
      Your concerns about more than one child reading from the pipe at the same time made things click for my co-worker. Once he read that he switched to using message queues which turned out to be simpler and easier to read. Thanks for the help!!!