Why does the second piece of code does not create 7 processes just like the first code? Anywhere it says that fork()'s child process runs exactly from the same point as the parent. Shouldn't this mean that the second fork() in the if statement should run inside the child as well?
This piece of code outputs:
int a = fork(), b = fork(), c = fork();
if (!a || !b || !c) {
printf("msg: pid = %d\n", getpid());
}
return 0;
outputs:
msg: pid = 28740
msg: pid = 28737
msg: pid = 28738
msg: pid = 28742
msg: pid = 28739
msg: pid = 28741
msg: pid = 28743
while the following piece of code:
if (!fork() || !fork() || !fork()) {
printf("msg: pid = %d\n", getpid());
}
return 0;
outputs:
msg: pid = 29385
msg: pid = 29386
msg: pid = 29387
In the parent process fork()
always evaluates to the PID of the child process. And in the child process it always evaluates to zero. As a PID cannot be 0, the return value of fork()
is always inherently truth-y in the parent process and always false-y in the child process.
When you couple fork()
with the logical not (!
) and logical or operator (||
), the net effect is that in the parent the !fork() || ...
statement always executes all three forks(), and does not enter the body of the if
as it is equivalent to (0 || 0 || 0)
. However, in the child, at the point that the child starts executing, the last executed !fork()
evaluates to a truth-y value, and so the logical or operator short circuits and stops executing the rest of the conditional statement, and instead enters the body of the if
statement. In the children, the conditional statement evaluates as thus:
if (true || <last two forks not executed>)
if (false || true || <last fork not executed>)
if (false || false || true) <nothing left to execute in conditional>
if (false || false || false) <if body not executed>
In the former example you give, all forks()
are executed unconditionally, and so seven descendent processes are created (not all of which are direct children of the parent).