I've a very specific question about fork system call. I've this piece of code:

int main (void) 
{
    for (int i = 0; i < 10; i++) {
        pid_t pid = fork ();

        if ( !pid ) {
            printf("CHILD | PID: %d, PPID: %d\n", getpid(), getppid());
            _exit(i + 1);
        }

    }

    for (int i = 0; i < 10; i++) {
        int status;
        waitpid(-1, &status, 0);

        if (WIFEXITED(status)) {
            printf("IM %d AND CHILD WITH EXIT CODE %d TERMINATED\n",
                    getpid(), WEXITSTATUS(status));

        } 
        else {
            printf("ERROR: CHILD NOT EXITED\n");
        }
    }

    return 0;
}

which produces this output:

CHILD | PID: 3565, PPID: 3564
CHILD | PID: 3566, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 1 TERMINATED
IM 3564 AND CHILD WITH EXIT CODE 2 TERMINATED
CHILD | PID: 3573, PPID: 3564
CHILD | PID: 3567, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 9 TERMINATED
IM 3564 AND CHILD WITH EXIT CODE 3 TERMINATED
CHILD | PID: 3568, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 4 TERMINATED
CHILD | PID: 3569, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 5 TERMINATED
CHILD | PID: 3570, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 6 TERMINATED
CHILD | PID: 3571, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 7 TERMINATED
CHILD | PID: 3572, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 8 TERMINATED
CHILD | PID: 3574, PPID: 3564
IM 3564 AND CHILD WITH EXIT CODE 10 TERMINATED

which makes me wonder how fork really works and what code new processes really execute. Looking at the above output results, I can not understand:

  1. How does second for cycle prints before first for finish all iterations? I've also noticed this second for is always executed by parent process, which makes me wonder if while on first for cycle, if pid != 0 (which means parent process calling) second for cycle is executed (?)
  2. Why does CHILD processes are not sorted printed by PID?

So, bottom line, how does fork really works and who executes what?

up vote 7 down vote accepted

When you fork, the kernel creates a new process which is a copy of the forking process, and both processes continue executing after the fork (with the return code showing whether an error occurred, and whether the running code is the parent or the child). This “continue executing” part doesn’t necessarily happen straight away: the kernel just adds the new process to the run queue, and it will eventually be scheduled and run, but not necessarily immediately.

This explains both behaviours you’re asking about:

  • since new processes aren’t necessarily scheduled immediately, the parent might continue running before any child gets a chance to run;
  • creation order doesn’t have much (if any) impact in the run queue, so there’s no guarantee the child processes will run in the order they’re created.
  • I think I understand the not sorted prints, but to clarify: is the second for only executed by parent because child processes always reach return status because of _exit invocation? – user220019 Mar 9 '17 at 15:30
  • Ah, I didn't realise you were asking about that too. Yes, the children exit as soon as they print their message, because of the call to _exit. So the second for loop is only run by the parent. – Stephen Kitt Mar 9 '17 at 15:34
  • perfect! just to clarify two more aspects, if I may : 1) going deeper in your main answer: I've no guarantees that child processes will print by order, but I have guarantees that they are created by order, correct? (for example, if I create a int array[10] and in first for cycle I do pids[i] = fork() I can guarantee that array is sorted by child processes creation, right?); 2) I realize that if I remove _exit() call things go messy, with 1023 new processes created. Does this mean that if _exit() is not called, children processes aren't naturally terminated/killed for good? – user220019 Mar 9 '17 at 15:51
  • (sorry for being abusive perhaps, but you are clearing out many things this moment) – user220019 Mar 9 '17 at 15:51
  • Yes, the children are created in order, so if you store the pids you can wait for them in the right order. If you remove the _exit call, you will indeed have many more new processes created. Children just continue executing their code, in the same way as any process; so they’ll continue until they explicitly exit or they return from main. – Stephen Kitt Mar 9 '17 at 15:56

Your Answer

 

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.