That system
runs in a parent process† after the fork
, while the child process falls through right away. Since the @pids
is written to in one of the processes (the parent) the other one (the child) doesn't see this change to a parent's variable; its own @pids
stays as it was before the if
split the processes.‡ Thus since its @pids
is empty the child process just passes over that loop.
Then, in that child process that fell through and went over the empty loop, the right-shift (>>
) is done on an undefined value ($return_code
has not been assigned yet) -- for what you'd get a warning if you had use warnings;
on -- and the result of that is converted to 0
, which is then assigned. And then that is returned.
So that zero is bogus, meaningless.
Do push @pids, $pid
before the if
condition, right after fork
.
Also, you need to exit one of these processes -- commonly the one inside the if
condition -- or you'll have two processes executing all code that follows.
Another option is to add an else
branch for the child, in which the child process exits. Then all is well again since the parent will eventually get to its @pids
list.
† It is common to select branches by
if ($pid == 0) { # child process enters this branch, parent does not
...
}
# parent process drops right here, since its pid is not `0`
In this question that is reversed, testing for true $pid
-- and so here the parent process enters the branch and the child drops right below it. That's OK as well of course and the discussion applies.
‡ As soon as a variable is written to the processes get their own copies.
But let's imagine that the other process (child) sees that change in @pids
(made in the parent). There would still be a problem -- there would be a race condition, as the child may well get to the loop over @pids
before the push @pids, $pid
in the parent (inside the if
branch) happens.