Source Code :
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main() {
if(fork() == 0)
if(fork())
printf("Hello world!!\n");
exit(0);
}
OUTPUT :
┌──(kali㉿kali)-[~/Desktop/System]
└─$ ./a.out
Hello world!!
Can anyone please explain me the flow of the Program ? I know what fork() does but I can't comprehend this source Code . Can anyone please share what exactly happens when fork() is invoked apart from saying it's just a copy.
fork()
is a system call. That means it's a part of the native library made available to the user by the underlying operating system (in this case, most likely the Linux kernel).
Processes under Linux are organized in a tree structure, such that every process has a parent (apart from the root one, called init
), and every process may have children. Every process is also uniquely idientified by a PID, just a number really.
Say you launch process 100, which executes the code you provided. While running, process 100 calls fork()
. What happens is the following:
fork()
call, whose return value is 0
. fork()
returning 0
indicates that the execution is continuing as part of the newly spawned process.fork()
call. But in this process, fork()
will have returned 200
. fork()
returning a non-zero value indicates that the execution is continuing as part of the parent process, and the returned value is the PID of the new child process.In any practical case, the PIDs won't be 100 or 200 but that's to get a rough idea. Let's continue with that idea anyway, and let's also rewrite your code as follows:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
int forkValue1 = fork();
if(forkValue1 == 0)
{
int forkValue2 = fork();
if(forkValue2)
{
printf("Hello world!!\n");
}
}
exit(0);
}
Now let's break down what this does at runtime, instruction by instruction, assuming your code is run by process 100 again.
Process 100:
int forkValue1 = fork();
fork()
is called! Process 200 is spawned by the kernel.fork()
into forkValue1
, because we're in the parent process, the one which issued the call to fork()
in the first place.if(forkValue1 == 0)
forkValue1
is 200, the condition evaluates to false, and the whole block is skipped.exit(0);
Now what happens from the perspective of process 200?
fork()
. Execution starts immediately after the originating fork()
call, which in this case returns 0 since we're in the child process. That value goes into forkValue1
.if(forkValue1 == 0)
forkValue1
is 0, the condition evaluates to true, and the block is executed.int forkValue2 = fork();
fork()
is called! Process 300 is spawned by the kernel.fork()
into forkValue2
, because we're in the parent process, the one which issued the call to fork()
in the first place.if(forkValue2)
forkValue2
is non-zero". Since forkValue2
is 300, the condition evaluates to true, and the block is executed.printf("Hello world!!\n");
exit(0);
Finally, let's see how it goes for process 300
fork()
. Execution starts immediately after the originating fork()
call, which in this case returns 0 since we're in the child process. That value goes into forkValue2
.if(forkValue2)
forkValue2
is 0, so the condition evaluates to false, and the block is skipped.exit(0);
The key takeaway in here is that the processes are basically duplicated from a system point of view, and the only difference in their execution flow is that for one of them, fork()
will have returned 0, and for the other, it will have returned something else.
This leads to a very common idiom in Linux programming:
if (fork() == 0)
{
/* Code for the newly spawned child process */
}
else
{
/* Code for the parent process */
}
See this question for additional info.