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

I have the following:
sub RUN { my $arg = $_[0]; fork; do stuff on my $arg; ($arg is a file, stuff is making a report) }
in MAIN::
RUN(arg1); wait; RUN(arg2); wait; RUN(arg3); wait;
The result:
arg1 is reported, then arg2 is reported twice , then arg3 is reported 3 times. Sugestions to make each RUN only run once? I want elegant use of Perl code, preferably something in the RUN subroutine, not a flag type deal after each RUN call.

Tommy O

Edit: chipmunk 2001-07-09

Replies are listed 'Best First'.
Re: Multiple forks get re-executed
by PrakashK (Pilgrim) on Jul 10, 2001 at 00:18 UTC
    You must explicitly terminate the child process that fork created, once it's job is done. Otherwise, it continues to exist.

    In your pseudo-code, the code after fork is executed by both the parent and the child. If you want only one of them to do "stuff" (usually child -- that's why you forked, right?), you must explicitly check the return code of fork to determine the identity of the process and assign "work" to it.

    fork returns the pid of the child process to the parent, and returns 0 to the child process.

    Please see below:

    sub RUN { my $arg = shift; if (fork) { # parent process # do whatever parent is supposed to do wait; } else { # child process do stuff on $arg; exit; } }
    In practice, you should check for possible errors in the fork call. Please see the camel book for an example (p. 715 in 3rd edition).

    /prakash

      Thanks. This is what I ended up using. The code is a generalized subroutine that does a task for my users, but it is at their discretion as to whether they wish to fork or not, as it is also at their discretion to choose where to reap their children. Tommy O
Re: Multiple forks get re-executed
by Anonymous Monk on Jul 10, 2001 at 00:23 UTC
    Yes, you must write a tasksub like so
    sub RUN { my$i;return$i||0if($i=fork)||!defined$i;die"\n"if"-".do #tasksub head { #your code here, you are forked already } }
    If you comment the line beginning with my you have a normal sub (that should return undef btw). Don't make the die to exit, because there are Situations where it's needed.
      Which Situations are those? Page 716 of Camel 3 states, in part:
      Be careful to end the child code with an exit...
      I'm not sure about the use of concatenation in the if, either. Do you often find yourself writing subroutines that may or may not need to fork?
        The situations are Resource-allocations in the parent (and caller) on behalf of the child, that the child must return to the pool on end, but wants to do in the caller because of lexical restrictions or clarity of writing.
        Do you often find yourself writing subroutines that may or may not need to fork?
        
        Of course in testing and debugging. Debugging a (multiply) forked sub is a PITA(TM).