Beefy Boxes and Bandwidth Generously Provided by pair Networks
Just another Perl shrine
 
PerlMonks  

Re: A Quick fork theory question

by ZZamboni (Curate)
on Jun 14, 2001 at 21:38 UTC ( [id://88525]=note: print w/replies, xml ) Need Help??


in reply to A Quick fork theory question

Of course you can :-) and if you are familiar with how it would be done in C (which I have the feeling you do, from your question), it should be easy to translate the solution to Perl. The semantics of fork and waitpid in Perl are identical to C (this also means that at least for waitpid the behavior might change between different systems).

On the other hand, managing multiple processes is always tricky, and you have the risk of things running amok if you make a mistake, and it may not be immediately obvious how to properly manage multiple subprocesses. You may want to look at some existing solutions such as Parallel::ForkManager or ForkBlock.

--ZZamboni

Replies are listed 'Best First'.
Re: Re: A Quick fork theory question
by E-Bitch (Pilgrim) on Jun 15, 2001 at 00:11 UTC
    Maybe I wasnt as informed as I thought... I am trying to run the following code:
    #!/usr/bin/perl -w $|++; print "Hello before fork\n"; #print first message $thiscount = 0; #counter for number of forks for($i = 0; $i < 2; $i++) #for loop to fork 2 procs { $thispid = phork(); #fork a proc, store the pid print "Just forked $thispid\n"; #tell us what you've done $thiscount++; #increment the fork count } $wpid = wait; #wait until children are finished print "i'm waiting on $wpid\n"; #tell us what you've done print "hello from after fork. I have forked $thiscount child processe +s.\n"; #final message from parent? sub phork() #subroutine for forking stuff { $cid = 0; #child id $count = 0; #number of times through. FORK: { print "i am about to start forking stuff. my id is $$, and i +have done this $count times\n"; $count++; #increment the number of times through if($pid = fork()) #parent process { print "Parent phorking child. I am: $$, and my child is $ +pid\n"; $cid = $pid; } elsif(defined $pid) #child processs { print "Hello from in phork. I am $$, and my parent is: $p +id\n"; return $$; } elsif($! =~ /No more process/) #error { sleep 5; redo FORK; } else #error { die "Cant phork: $!\n"; } } return $cid; #ship back the child id }
    my intentions are to fork 2 children, have them print out their process IDs, and return to the main part of the program, and then the main portion waits on the children to finish, then prints out that it too is finished. I get the following results.:
    [33] rk110759@sunray22: test.pl Hello before fork i am about to start forking stuff. my id is 15092, and i have done th +is 0 times Parent phorking child. I am: 15092, and my child is 15095 Just forked 15095 i am about to start forking stuff. my id is 15092, and i have done th +is 0 times Parent phorking child. I am: 15092, and my child is 15096 Just forked 15096 Hello from in phork. I am 15096, and my parent is: 0 Just forked 15096 Hello from in phork. I am 15095, and my parent is: 0 Just forked 15095 i am about to start forking stuff. my id is 15095, and i have done th +is 0 times i'm waiting on -1 hello from after fork. I have forked 2 child processes. Parent phorking child. I am: 15095, and my child is 15097 Just forked 15097 Hello from in phork. I am 15097, and my parent is: 0 Just forked 15097 i'm waiting on -1 hello from after fork. I have forked 2 child processes. i'm waiting on 15097 hello from after fork. I have forked 2 child processes. i'm waiting on 15095 hello from after fork. I have forked 2 child processes.
    Am i being ignorant, and my program is actually printing out what it I intended? and why does the message after the fork ("hello from after fork...") get printed out 4 times?
      First, inside phork(), you incorrectly try to get the parent id from within the child. Going by the Camel, 3rd ed., p. 715, the following change should be made:
      elsif(defined $pid) # Quoth the Elders: # "$pid is zero here if defined" { print "Hello from in phork. " print "I am $$, and my parent is: " . getppid ."\n"; return $$; }
      Secondly, you've already seen the others' comments on the problem with the children re-entering the loop and spawning their own children. Here's my take on what you can do to fix it. (I'm posting this as much to help you as to get told by others if it's a horrible idea, so caveat coder...)
      use strict; $|++; my $parent_id = $$; # Before forking, save the $parent_id my $totalcounts = 0; for(my $i = 0; $i < 2; $i++) # for loop to fork 2 procs { print "[$totalcounts == $i]\n"; # just to check... # if I am the parent... if ($$ == $parent_id) { #...fork a proc and store the pid my $thispid = phork(); } # I have now forked. If I am NOT the parent... if ($$ != $parent_id) { ## Note 'if'. An else/elsif ## WON'T work here! The ## kids would skip this. #...do whatever I want to do, but when done: exit; # Now the children have been stopped # before they could continue along the $i loop. } $totalcount++; #increment the fork count }
      Alternatively, add the exit() at the appropriate spot in phork().

      -- Frag.

      Okay, this may be difficult to follow along to; but I will do my best.

      When you fork, your children processes get an exact replica of the process. So, your first child gets spawned. Now, it has a copy of $i which has the value zero. So, it is spawned, it runs the phork() subroutine, and it returns to the for loop with a $i of 0. So, it beings to execute the loop; and your first child process forks its own child and that child (the first child of the first child of the parent) is spawned and it gets a copy of the memory block who has a $i of 1. This stuff happens some more with the second child of the parent and so on. What you want is something along these lines: (warning: untested)
      #!/usr/bin/perl -w use strict; my $childLimit = shift @ARGV; #get total number of children my @pids = (); #array of pids of children for(my $i = 0; $i < $childLimit; $i++) { if( !( $pids[$i] = fork() ) ) { # in the child callChildSub(); exit(0); # exit from the child process IMPORTANT } } foreach my $pid (@pids) { waitpid $pid, 0; } sub callChildSub() { print "I am the child with pid $$.\n"; }
      Of course, that needs some error-checking and such, but that should get you started.

      Jeremy
      Because your child *returns* (after it has done the printing) into the for loop, thereby (next iteration) phorking itself a child - and 2x2 makes 4. BTW it should exit or die"\n".

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: note [id://88525]
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others browsing the Monastery: (7)
As of 2024-04-23 10:13 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found