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,
we'll define some subroutiness to act as children and open a single pipe.#!/usr/bin/perl use warnings; use strict;
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 @kids = ( sub { print "First!", $/; }, sub { print "Second!", $/; }, sub { print "Third!", $/; }, ); pipe my ($in, $out);
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.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; }
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.close $out or warn $!; s/.$/??? says the child/, print while <$in>; delete $kid{+wait} while %kid;
I've tested this on Windows XP and Linux. It works on both.
After Compline,
Zaxo
In reply to Re: reading many file handles at once
by Zaxo
in thread reading many file handles at once
by Anonymous Monk
| For: | Use: | ||
| & | & | ||
| < | < | ||
| > | > | ||
| [ | [ | ||
| ] | ] |