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

Hello,

I need some help on file handles. If I open different processes and pipe them into file handles. Without using select (since select does not work well with windows), is there any other way I can read the input from the file handles when the input is ready? Thanks.

Replies are listed 'Best First'.
Re: reading many file handles at once
by Zaxo (Archbishop) on Jan 10, 2005 at 04:09 UTC

    One solution is to use a many-to-one pipe. That involves some manipulation of duplicated handles in the child process, so you'll have to call fork instead of magic open.

    After preliminaries,

    #!/usr/bin/perl use warnings; use strict;
    we'll define some subroutiness to act as children and open a single pipe.
    my @kids = ( sub { print "First!", $/; }, sub { print "Second!", $/; }, sub { print "Third!", $/; }, ); pipe my ($in, $out);
    Now we start breeding children. Each will close the $in handle, select the $out handle as the default, set up autoflush on it, and then call their sub. We definitely need to prevent zombies, since the kids will all finish before the parent does, so we start by declaring a hash where we will keep their pid's.
    my %kid; for (@kids) { my $cpid = fork; defined $cpid or warn("Couldn't fork"), next; $cpid or do { # child close $in or die $!; select $out; $| = 1; $_->(); exit 0; }; $kid{$cpid} = undef; }
    The select statement is the one-arg kind, which windows should handle ok. Back in the parent, now, we have an unwanted $out handle, a single $in handle that the kids are all fighting to talk on, and a hash to remind us of the kids' names. Wrapping up, we close $out, listen to the kids in turn, decorate their messages to show who's repeating them, and finally call wait enough times to bury them all safely. We must be careful not to die before that.
    close $out or warn $!; s/.$/??? says the child/, print while <$in>; delete $kid{+wait} while %kid;
    Many-to-one pipes like this will keep their messages' integrity in flush-sized chunks. So long as they are shorter than than an I/O buffer and end with $/, they will be read as distinct. You may want to have the kids tag their messages to identify the source.

    I've tested this on Windows XP and Linux. It works on both.

    After Compline,
    Zaxo

Re: reading many file handles at once
by NetWallah (Canon) on Jan 10, 2005 at 00:19 UTC
    If you are considering redesigning your program, I'd suggest "use threads;" instead of processes, and Thread::Queue for pipes and file handles.

    Sample code is in this node.

        ..."I don't know what the facts are but somebody's certainly going to sit down with him and find out what he knows that they may not know, and make sure he knows what they know that he may not know, and that's a good thing. I think it's a very constructive exchange," --Donald Rumsfeld

Re: reading many file handles at once
by BrowserUk (Patriarch) on Jan 10, 2005 at 00:12 UTC

    What alternative are you looking for?

    Rather than asking for an alternative, why not post the code that you are having problems with, and let us help you correct it?


    Examine what is said, not who speaks.
    Silence betokens consent.
    Love the truth but pardon error.
Re: reading many file handles at once
by ZlR (Chaplain) on Jan 10, 2005 at 09:25 UTC
    Hello,

    With Perl 5.8 you could use Win32::Job .

    It enables you to redirect the stdin of a child process .

    ZlR.

Re: reading many file handles at once
by zentara (Cardinal) on Jan 10, 2005 at 20:56 UTC
    I don't know if it will help you or not, but IPC::Run is supposed to work well on MSWindows. Maybe you could use that?

    I'm not really a human, but I play one on earth. flash japh