http://www.perlmonks.org?node_id=969488

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

So consider the following: It's not really secure, so don't use it. It's not Taint safe, it's just for discussion (let me know if this is the wrong section, apologies in advance).
use strict; use Parallel::ForkManager; use IO::Handle; my ($something, $somemaxnum) = @ARGV; pipe(DAREADER, DAWRITER); DAREADER->autoflush(1); DAWRITER->autoflush(1); sub onFinish { while (<DAREADER>) { ## read data from children print; } } my $fkmngr = new Parallel::ForkManager($somemaxnum); $fkmngr->run_on_finish(\&onFinish); for (1..$something) { $fkmngr->start and next; # child close DAREADER; print DAWRITER "some text"; close DAWRITER; } close DAWRITER; $fkmngr->wait_all_children; close DAREADER; __END__
Ok so this script deadlocks. Can anyone guess why?

What I find is this. With a short amount of text, it's fine.. but when the text gets larger or the forks end at various times the run_on_finsh subroutine doesn't leave the while loop. The while loop actually reads data from multiple forks, not just the one that finished (run_on_finish tells you the pid that just finished. On a few occations this number did not change yet data indicated that it was reading writes from a different fork which means that the funciton was executed once, after one fork ended).

However, the forks are still <defunct> (on solaris... ymmv), but the parent process is waiting for a read. Which means that <> is broken, I think, with pipes, because even though each fork has sent a close() to DAREADER, the parent process never receives EOF, and thus the subroutine never exits, wait() is never called.. etc... I mean yes, each file handle is copied however wouldn't close() send EOF down the pipe? Is this really broken or am I missing something?

The way I've worked around it is do ye olde 'dot-alone-on-a-line' trick and have each fork send a final "\n." which calls a last in the onFinish subroutine:

sub onFinish { while (<DAREADER>) { last if /^\.$/; print; } }
This will exit the subroutine, allow wait() to be callled, new forks to start and Parallel::ForkManager to do its thing (a great great module IMO!), however I can only guess why I need to do this DGRAM style and EOF just isn't failing the <> test.