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