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

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

I am trying to create a program that manages child processes by sending data to their standard in and monitoring the output from stdout. It works great on Unix and even under cygwin but it dies horribly under ActivePerl for Windows (5.8-5.8.3). I've created this sample script which demonstrates the problem:
if ($pid=fork() ) { select(undef,undef,undef,.1); print "parent\n"; } else { open (STDOUT, ">test.txt"); system("echo child"); }
Under unix and cygwin you get the expected bahavior, a file test.txt with "child" in it and the program prints "parent" as it's output. Under Windows I get no output and a file that has both "hi" and "parent" in it. From what I've read about fork emulation under Windows it sounded like this should work. In fact, if I try the example listed in perlfork under Windows it doesn't work! Does anyone know what's going on here?

Replies are listed 'Best First'.
Re: Windows filehandles and fork
by Koosemose (Pilgrim) on Apr 09, 2004 at 01:18 UTC

    I'll be honest, I'm not entirely certain what is going on here, but here are two versions that at least seem to work. Perhap's some kind monk can tell me (and the OP) why these seem to work properly.

    if ($pid=fork() ) { select(undef,undef,undef,.1); open (STDOUT, ">test.txt"); print "parent\n"; } else { print "child\n"; }

    ... and...

    if ($pid=fork() ) { #select(undef,undef,undef,.1); print "parent\n"; } else { open (STDOUT, ">test.txt"); system("echo child"); }

    update: commented out the select line in second example.

    Just Another Perl Alchemist
      The first one works as expected for me. Parent goes into the file, child goes to STDOUT. The second one does the same as mine. I've tested it on Activeperl 5.8.2 on WinXP Home and 5.8.3 on Win2000 Pro. It prints both child and parent into test.txt even though, from what I understand, the child shouldn't be able to manipluate the parent's STDOUT.
      Commenting out the select line makes it likely that the parent will run it's print before the child does the open(STDOUT) which is causing the problem. You are then in a nasty state because then whenever the child get's arround to opening STDOUT, the parent's print statements will be spontaneously redirected. This is bad behavior.

      It looks to me like something is broken in the fork emulation in ActivePerl.

        I'd most likely agree with you, but to be honest I don't know to much about fork and how it's supposed to work. I am still in the process of studying the appropriate chapter in the Camel. But I do recall it mentioning that forks in perl were implemented with threads of some sort ( ithreads I think ) but was bent to more resemble a Unix Fork.

        I do hope I made it clear in my first post that I didn't really know what was going on. I am however, curious why my first example seems to run as expected, or is this also a situation of the open happening after the other process has already printed it's message.

        I'm also not entirely clear as to what select is doing. I can't seem to find any mention of that particular form in perlfunc. And neither of the two mentions in perlipc seem to say what they're doing.

        Update: Ack, Just realized I should probably look in the camel, and managed to dig up what select is doing, apparently it's just putting a minor delay in one of the processes, I assume the purpose in the initial verion was to make certain that one process' print happened after the other's open, so it would seem that both my examples seemed to have the desired effect only due to (in one case) the random chance of one of the print's happening before the open. And in the other case because the open itself was delayed, making certain that the other process got it's print out beforehand. bleh...

        Just Another Perl Alchemist
Re: Windows filehandles and fork
by Koosemose (Pilgrim) on Apr 09, 2004 at 07:26 UTC

    Ok, after a bit more research I would have to agree with esskar, apparently win32 children don't get their own STDOUT due to being implemented as threads. It would seem that the simplest solution would be to open a brand new filehandle in the child and just select it, as follows (which of course could be done in the $fh method, but I'm more comfortable with FH):

    if ($pid=fork() ) { select(undef,undef,undef,.1); print "parent\n"; } else { open (CHLDOUT, ">test.txt"); select CHLDOUT; system("echo child"); }

    Now that I know better what's going on I'm pretty confident that this version will not only work as expected, but will actually work due to being done proper, instead of due to accident :)

    Just Another Perl Alchemist
Re: Windows filehandles and fork
by esskar (Deacon) on Apr 09, 2004 at 01:19 UTC
    i guess that under windows fork is implemented using threads so the child does not have his own STDOUT. Why are you dont you open a new filhandle in each child process and better use $fh as a handle not the FH thing.

    just my 50 cent..
      i guess that under windows fork is implemented using threads so the child does not have his own STDOUT.
      My guess is that that is indeed what is happening.
      Why are you dont you open a new filhandle in each child process
      Because he wants to use it together with system(), and that won't work as intended, with any other filehandle.

      Update: Gee, Koosemose appears to be right, this does seem to work right (at least on Win98):

      open CHILDOUT, ">test.txt"; select CHILDOUT; system('perl -le "print q(Hello!)"');

      I think that would indeed solve it.

Re: Windows filehandles and fork
by sgifford (Prior) on Apr 09, 2004 at 14:46 UTC