mp3car-2001 has asked for the wisdom of the Perl Monks concerning the following question:

My first question, so try not to kill me. I did search first though:) What I'm working on is a multi-threaded program to do some network tasks. I have to connect to a number of hosts to complete these tasks, I don't think what they are matters and would only confuse. So I have a stack/array that has all of the hostnames in it and I want each child process to get a different one of each stack. Basically my plan is (rough pseudocode)
@array_of_hosts while(hostsleft){ fork() if child{ pop @array_of_hosts and go to town with that host } parent code{ pop @array_of_hosts and throw away value, continue on with loo +p } }

My idea is that the parent pop's the stack right after the fork, so that the value the child process got is no longer in the stack. Is this the right thing to do, or is there a "right thing to do"?

many thanks,
Joe

Replies are listed 'Best First'.
Re: Using a stack with fork()
by merlyn (Sage) on Jan 06, 2001 at 06:08 UTC
    Why not just:
    foreach my $host (@arrayofhosts) { defined (my $pid = fork) or die "Cannot fork: $!"; unless ($pid) { # go to town with $host exit 0; # very important!!! don't let it get past here } }

    -- Randal L. Schwartz, Perl hacker

      because that would fork-bomb a machine if the array is large.

      i did this in a previous script:

      my $fork_num = ( $#hostlist <= MAXFORK ? $#hostlist : MAXFORK ); for ( 0..$fork_num ) { ## ## create bi-directional socket for parent/child communication my $to_child = IO::Socket->new(); my $to_parent = IO::Socket->new(); socketpair($to_child, $to_parent, PF_UNIX, SOCK_STREAM, PF_UNSPEC) or die "Couldn't create socket pair: $!\n"; my $pid; if ( $pid = fork ) { ### parent process undef $to_parent; $to_child->autoflush; $children{$pid} = $to_child; sleep 1; next; } else { ### child process undef $to_child; undef %children; $to_parent->autoflush(1); local $SIG{PIPE} = sub { print " CAUGHT PIPE\n\n"; die "Signal caught in +Child $$: $!\n"; }; ## ## main processing occurs in the subroutine. &process_config_job($fork_num, $to_parent); } }

      the child processes have a sub getnexthost() which asks the parent for another hostname.

      the parent process has a subroutine to read the request for a new hostname then send it.

      i don't like the 'fork foreach' idiom. good way to crash a box.

Re: Using a stack with fork()
by Fastolfe (Vicar) on Jan 06, 2001 at 06:10 UTC
    Why not do:
    while (host = pop array_of_hosts) { fork if child { work on host exit } }
    Of course, this only gets work done, and kind of makes it difficult for the children to report back to the parent with results. If you want that functionality you probably want to make use of something like pipe or a piped open call.
Re: Using a stack with fork()
by mp3car-2001 (Scribe) on Jan 06, 2001 at 06:17 UTC
    Thanks to both of you, neither idea hit me. I'm not concerned with the output from the child, as it does its own error checking and checks in its status to a mysql database. The parent is going to take care of the errors after the last child reports in.

    Thanks a lot from a wannabe monk with 0 reputation :)

      Hi,

      My idea is that the parent pop's the stack right after the fork, so that the value the child process got is no longer in the stack. Is this the right thing to do, or is there a "right thing to do"?

      I'm not all that familiar with fork() (I spend most my time on Win32). But wasn't Fastolfe's suggestion basically what you asked for? except more efficient.

      The while (host = pop array_of_hosts)does the pop before the child is created, all the child needs to know is the value of $host, it doesn't need to pop, because the parent has already taken care of it.

      Update: I've just read up a bit on fork. If I were you, I would develop Merlyn's snippet. It's a little less pseudocode than Fastolfe's but basically the same. You could add a sleep() in there for the parent so you don't spawn too many children and overload the CPU which concerned geektron.

      To just explain Merlyn's a bit further (and alter it a bit to utilise pop):
      while (my $host = pop @arrayofhosts) { # $host is no longer in the +array defined (my $pid = fork) or die "Cannot fork: $!"; # self-explanato +ry unless ($pid) { # only the child will execute this code from here ... # do some things with $host exit 0; # very important!!! don't let it get past here # to here. At this point, the child process will terminate ... } # The parent continues here after forking the child # here it can do what it wants. # you can rest here a while so you don't have too many zombies sleep (10); # now do some more things before forking the next child process }