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

Hi everybody, I am back with the same problem, but now I have a short script that demonstrates the issue:
#!perl -w my $fn = 'fork_test.txt'; my $pid; if ($pid = fork) { print "Hello from ithread 1\n"; open(STDOUT,'>',$fn); system('ipconfig'); close STDOUT; waitpid($pid,0); } else { die 'Couldn\'t fork!' unless defined $pid; open(READ,'<',$fn); print "Hello from ithread 2\n"; my $l; do { undef $l; my $i = 0; while(!defined($l)) { my $slp = int(($i++ + 9) / 10); sleep($slp); $l = <READ>; }; print $l; } until($l =~ /Gateway/); close READ; }
With Perl 5.6 it works correctly. Both hellos are printed to the screen and you will also see the output of ipconfig to be printed to the screen. But note, that the ipconfig output goes to the file first and then it is read from the file being printed to STDOUT.
With Perl 8.0, this script works incorrectly. Usually, only "Hello from ithread 1" is printed to the screen and everything else goes to the file. However, sometimes "Hello from ithread 2" gets printed to the screen too. It depends on whether the print occurs before the STDOUT gets redirected in the ithread 1. So, it looks like that in spite of file handles being dupped they are shared through some pointer data structure. It really seems that fork is not compatible with the new PerlIO.
What are your thoughts? --Dave

update (broquaint): changed <small><pre> to <code>

Replies are listed 'Best First'.
Re: fork on Windows (Perl 5.8)
by BrowserUk (Patriarch) on Jun 30, 2003 at 19:14 UTC

    I agree that you have found a bug. I've reduced your testcase even further and the fact that re-opening STDOUT in one fork is affecting the STDOUT in the other fork is clearly demonstrated.

    #!perl -slw use strict; $|++; if( my $pid = fork ) { print 'Hello from ithread 1'; sleep 5; open STDOUT, '>', 'fork_test.txt' or die $!; print STDERR 'STDOUT opened to file'; waitpid($pid,0); } else { die 'Couldn\'t fork!' unless defined $pid; for( 1..10 ) { sleep 1; print 'Hello from ithread 2'; } } __END__ P:\>perl58 270224.pl8 Hello from ithread 1 Hello from ithread 2 Hello from ithread 2 Hello from ithread 2 Hello from ithread 2 STDOUT opened to file P:\>perl5.6.1 270224.pl8 Hello from ithread 1 Hello from ithread 2 Hello from ithread 2 Hello from ithread 2 Hello from ithread 2 STDOUT opened to file Hello from ithread 2 Hello from ithread 2 Hello from ithread 2 Hello from ithread 2 Hello from ithread 2 Hello from ithread 2

    The difference between the 5.6 and the 5.8 versions speaks volumes. As Thelonius said, if all you wanted to do was report the bug, then type "Perlbug" and follow the instructions.

    If you are hoping for a work-around then I offer this.

    ... else { die 'Couldn\'t fork!' unless defined $pid; close STDOUT; open STDOUT, '>', 'con' or die $!; ... }

    Re-opening STDOUT to 'con', assumes Win32, on unix you'd probably need '/dev/tty' or similar.

    Not pretty and it shouldn't be necessary, but it should get you over the hump until you get a proper fix.


    Examine what is said, not who speaks.
    "Efficiency is intelligent laziness." -David Dunham
    "When I'm working on a problem, I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong." -Richard Buckminster Fuller


Re: fork on Windows (Perl 5.8)
by Thelonius (Priest) on Jun 30, 2003 at 17:23 UTC
    Yes, that's definitely a bug in Perl. Your post is not clear, but when I try it out, everything that's printed to STDOUT in the child thread goes into the file "fork_test.txt". You should submit a bug report. There's a "perlbug.bat" to help you do that.

    There are probably workarounds to this, but it's not completely clear what you're trying to do. I realize this is just a bug demonstration program, but it has a terrible race condition. If you just want the output of ipconfig, why don't you just say $l = `ipconfig`?

      I do not know what you mean by "race condition". As you said, it is just a bug demo. In real, the same events as these in this short script occur in different objects. The code is very complicated and I don't want go into describing it.
        Race Condition. In this particular case, one process is opening a file that may or may not be created yet. If it does succeed in opening it, it may read the contents of the previous run of the program. If it doesn't succeed, it loops forever.
Re: fork on Windows (Perl 5.8)
by fglock (Vicar) on Jun 30, 2003 at 17:13 UTC

    This is from a script I wrote. It works both in Windows and Linux.
    This is not exactly a "fork", but it is portable:

    if ($^O =~ /win32/i) { # win32 uses "start" my $cmd = "start \"Glynx-$children\" /MIN /LOW \"$^X\" \"$0\" +--slave"; print "$cmd\n" if $VERBOSE; print " [ FORKING: $children ]\n" if $VERBOSE; `$cmd`; } else { undef $pid; if (!defined($pid = fork)) { print " [ cannot fork: $! ]\n" unless $QUIET; # exit 0; } elsif ($pid) { print " [ FORKING: $children ]\n" if $VERBOSE; # print "begat $pid"; # print "I'm the parent"; } else { # print "I'm the child"; } }