So fork splits one process into two processes, both of which are in the exact same state, the same place in the code, etc.* In the parent process, fork() will return the PID of the new child process it forked. In the child, fork() will act as though it returned 0. I say "act as though" since, from the child's perspective, fork wasn't really called from that child process, that child process came into being immediately after the fork call from the parent.
One thing that always really helps me in following like this with complex forking behavior is to print out the PID and parent's PID (PPID) to track who came from who and who is printing what. Do that with everything you print. For example:
Code:
print("The process that started it all is PID = %d\n", getpid()); // put this above the while loop
printf("PID = %d, PPID = %d, y = %d\n", getpid(), getppid(), y); // replace the line in the while loop with this
It's not 100% portable/safe to assume you can print a PID as an integer, but it will probably work, if not print it as a long int or long long int (with necessary casting).
For the first program, the code enters the while loop, x and y are 10, and count is 1.
- Assume the initial parent program is process A.
- x is its initial value, 10 (non-zero), so it takes the "if" branch and forks, and you have two processes, A (parent) and B (child). After the fork, both processes add 10 to y, giving 20 in each process. They both print it out, add 1 to counter (making it 2 in each process) and continue into the next iteration of the loop.
- Process A was the parent last time, so fork return the PID of the child process (B), so x is non-zero. That means it takes the "if" branch again. So process A forks again, and has a second child process, C (a "sibling" process to B). Both A and C add 10 to y (making it 30 in processes A and C). They print y and add 1 to counter, making it 3. The loop terminates and processes A and C exit.
- Process B was the child, so fork returned 0 to it. That means x was 0, and the second time through the loop, it takes the "else" path. It forks a child process, process D (A's "grandchild", C's "nephew"), and both of those processes add 50 to y, making it 70. They each print that out, add 1 to counter, making it 3 and the loop terminates. They both exit and everything is now finished.
Now, I put those steps in a numbered list, but really, they can, and often do in practice, happen in a mixed up order. The reason is, the OS doesn't guarantee any particular order of execution for the processes that are running, even if one is a prent/child of another. Thus, it's possible that A adds 10 to y, but then B executes and forks, and D adds 50 to y then prints that out, before A gets a chance to print out y = 20.
Add a bunch of debugging output to the second program, and include the PID and PPID in each line, and see if that helps you track it. Try to figure it out on your own now, and come back if you need any more help. I'll be back in the morning, if somebody else hasn't stepped in to help.
Hope that all makes sense (I always find these things difficult to explain).
* There are a few ways in which the parent and child process differ, like PID, memory locks, semaphores, pending signals, etc. Read about them in the fork man page:
fork(2): create child process - Linux man page.