SPUG: Question on fork() and pipe()

Marc M. Adkins Marc.M.Adkins at Doorways.org
Mon May 13 12:48:14 CDT 2002


Looks like each time you go into fork_child() you read the pipe until it
closes.  So you won't exit fork_child() and go on to spawn the next child
until the first child dies and closes its pipe.

You need to create a list of pipe read streams at the parent process level
and use select() to wait on all of them at once.  I'm thinking fork_child()
should return a reference to the read stream to the parent process.  Check
out the doc on select().

Marc M. Adkins

> -----Original Message-----
> From: owner-spug-list at pm.org [mailto:owner-spug-list at pm.org]On Behalf Of
> Dwyer, Sean
> Sent: Monday, May 13, 2002 9:22 AM
> To: 'spug-list at pm.org'
> Subject: SPUG: Question on fork() and pipe()
>
>
> All,
>
> 	I have run into a bind on a control structure I am working with.
> Although I have a work around, I would rather use the pipe() solution so I
> can pass more complex data back to the parent process. The test code is
> below. Here is what is happening. The test sequence should spawn
> 5 children
> and as they die off replace them to maintain a running count of 5
> until the
> whole list (in this case a simple counter totaling at 20) is complete.
> Without the pipe() for communication between the children and the
> parent it
> acts just as it is supposed to. When I add the pipe in the processes
> serializes.
>
> 	My workaround is to use the exit status to give partial information
> back to the parent. But .. using the pipe allows me to pass more data back
> to the parent for later processes. If I use exit status then I
> will need to
> send the additional output to flat file so the parent can pick is up later
> and I would rather not do that.
>
> 	I have noted that from the OS (HPUX 11.00) side that the parent goes
> into a sleep state waiting on the pipe. Is there a way to leave the pipe
> open so that the children can talk back to the parent and still
> parallelise?
> If so what am I missing and how do I do it. Thanks in advance for
> any help.
>
> Sean Dwyer
>
> Data Base Administrator
> Customer Operations Support
> National Data Center Operations
> AT&T Wireless Services, Inc.
> Bothell, Washington
> Desk-425.288.7313
> Cell-206.601.5465
>
> #!/usr/local/perl5/bin/perl -w
>
> use POSIX ":sys_wait_h";
> use IO::Handle;
> use strict;
>
> $| = 1;
>
>
> my ($exit_val, $signal_num, $dumped_core);
>
> $SIG{CHLD} = \&child_track;
>
> my $DEBUG = 0;
> my $counter = 0;
> my $child = 0;
>
>
> print "\n## The parent process is: $$ \n";
>
> ##
> ## I have set a for loop here to take the place of the array
> ## that I really process in order to limit my number of iterations
> ##
> for (my $i = 1; $i <= 20; $i++) {
>   $counter++; # increase the counter because we are about to fork a child
>   print "COUNTER: $counter  \n";
>   &fork_child(); #fork the child passing in a vaiable
>   while ($counter >= 5) {
>     sleep 1; #sleep the processes so that we don't spin up the CPU
>     while ((my $child = waitpid(-1, -2)) > 0){1;} #wait on 1, any 1 child
>                                                   #to exit
>     }
>   }
>
> waitpid(-1, 0); # wait on all children to exit before ending.
>
>
> sub fork_child {
>   FORK: {
>
>     pipe(READER, WRITER);
>     WRITER->autoflush(1);
>
>     if (my $pid = fork()) { # parent here
>       close WRITER;
>       chomp(my $line = <READER>);
>       print "There Parent pid $$ just read this: '$line'\n";
>       close READER;
>       next if $child == 1; # Do not fork a child from a child
>       }
>     elsif (defined $pid) { # $pid is zero here if defined
>                            # child here
>       $child = 1;
>
>       sleep int(rand 10); #this is where the real work would go
>                           #randomize the sleep so the children don't
>                           #all exit at once.
>
>       close READER;
>       print WRITER "Child pid $$ is sending this";
>       close WRITER;
>
>       exit 100;
>       }
>     elsif ($! =~ /No more process/) { # EAGAIN, supposedly recoverable
>                                       # fork error
>       sleep 5;
>       redo FORK;
>       }
>     else { # weird fork error
>       die "Can't fork: $!\n";
>       }
>     }
>   }
>
> sub child_track {
>   my $pid = waitpid(-1, 0);
>   if ($pid == -1){return;} #no children have exited
>   elsif (WIFEXITED($?)) {
>     $exit_val = $? >> 8;
>     $signal_num = $? & 127;
>     $dumped_core = $? & 128;
> #    print "\$pid = $pid\n";
> #    print "\$signal_num = $signal_num\n";
> #    print "\$exit_val = $exit_val\n";
> #    print "\$dumped_core = $dumped_core\n";
>     print "Process exited\n";
>     $counter --; #decrease the counter so that you can spawn another
> processes
>     return;
>     }
>   else {print "False alarm on $pid";} #any other values are
> considered false
>
>   $SIG{CHLD} = \&child_track; #re-install the handler
>   }
>
>
>  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
>      POST TO: spug-list at pm.org       PROBLEMS: owner-spug-list at pm.org
>       Subscriptions; Email to majordomo at pm.org:  ACTION  LIST  EMAIL
>   Replace ACTION by subscribe or unsubscribe, EMAIL by your Email-address
>  For daily traffic, use spug-list for LIST ;  for weekly, spug-list-digest
>      Seattle Perl Users Group (SPUG) Home Page: http://seattleperl.org
>
>


 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
     POST TO: spug-list at pm.org       PROBLEMS: owner-spug-list at pm.org
      Subscriptions; Email to majordomo at pm.org:  ACTION  LIST  EMAIL
  Replace ACTION by subscribe or unsubscribe, EMAIL by your Email-address
 For daily traffic, use spug-list for LIST ;  for weekly, spug-list-digest
     Seattle Perl Users Group (SPUG) Home Page: http://seattleperl.org




More information about the spug-list mailing list