in reply to Waiting for an External Program to Finish Executing

The general definition of a fork is that a thread spawns a process that begins execution from the same program location as its parent, while the parent then continues in parallel.

Your code calls the perl fork function six times, three of which are controlled by returning the pid and issuing a waitpid to hold up parent execution until completion of the child. But not only will these children run through to the end of the code unchecked, but the three uncontrolled forks will triplicate everything from where they are placed - I don't dare to test (or rather inflict) your code on my machines under these circumstances, but if you were to place a sleep 60 at the end of the code and then repeatedly examine what is running using the ps command, I wager you will see far more parallel processes being spawned than you imagine should take place even after reading the above definition.

To fix this code in the simplest way:

1) yes, as already replied, replace all exec with system BUT

2) also remove all "unless fork" lines reducing the code to a single non-parallel process.

-M

Free your mind

  • Comment on Re: Waiting for an External Program to Finish Executing

Replies are listed 'Best First'.
Re^2: Waiting for an External Program to Finish Executing
by sgifford (Prior) on Nov 11, 2005 at 17:25 UTC
    Are you sure? It looks to me like all of the children either exec or die, which will stop them from executing any more code than they're intended to.
      If you look at the manual, you'll see that fork either returns the pid (and spawns a child) or undef if the fork was unsuccessful causing the code after the unless to finally execute, i.e. whenever the system is being sufficiently thrashed to get an undef() back from fork. Note also the conditions under which the manual states that zombies will be accumulated. The OP code meets the criteria for a zombie factory of von Neumann proportions. In fact the intended functionality only gets executed whenever there is a spawn error and sufficient spawn errors are generated to cause "unless" to function precisely because this code is thrashing the machine enough to cause such errors in turn enough to cause the branches with execs to be executed approximately in parallel, because the spawn error cirmsumstances will occur simultaneously of course. Furthermore, the OPs actual symptoms are explained by this analysis but conflict with yours.

      -M

      Free your mind

        if doesn't just check for fork returning undef; it also checks for returning 0, which is what fork does in the child. From the manual:
        (fork) returns ... 0 to the child process,

        So this code is creating three processes:

        • Parent: first fork returns nonzero $pid, parent executes waitpid($pid). This returns very quickly, since the child exits almost immediately (though not the grandchild).
        • Child: First fork returns zero in child, second fork returns PID of grandchild, child exits.
        • Grandchild: First fork returns zero in child, second fork returns zero in grandchild, grandchild either exec's or die's.
        When the grandchild finishes, its parent is already gone, so it's been reparented to init, which notices its death and waits for it, avoiding a zombie.

        The OP's problem is that he's waiting for the child but running the long-running process in the grandchild. The fix is to eliminate the second fork, and just do the work in the child; the purpose of a second fork is to do something in the background without having to wait for it, which is what the OP is trying to avoid.

        Here's a small example:

        Here's a version which does what I believe the OP wants.

        warn "PID $$ (parent) forking\n"; unless ($pid = fork) { warn " PID $$ (child) exec'ing\n"; exec "sleep 5"; die "Couldn't run getSite.pl"; } warn "PID $$ (parent) executing waitpid\n"; waitpid($pid,0); warn "PID $$ (parent) done.\n";

        But, this is completely equivalent to system, so why not just use that?