The fork() system call allows one process, the current running parent process to create a new child process. A duplicate is made of the parent process. The child obtains the exact copies of its parentโs memory segment.When the fork() system call is invoked, a new process is created with an identical memory layout to that of its parent.
Syntax of fork():
pid_t fork(void);
In parent, it returns the childโs process ID is returned to the parent and 0 is returned to the child on success or returns -1 on error.
The execution continues from the point where the fork () is returned. But, it is important to remember that, upon the successful call of the fork function, two processes will be under execution at any given point in time. Note, once the fork is called, both the parent and child a race condition will start where whichever process gets the time slice, gets the CPU. We need to use synchronization techniques if we want to the fork in desired manner.
The code:

Output:

As you can see in the below image, the 3402 and 3401 are run by a.out concurrently. This process tree is obtained by running the command ps axjf.

In Parent
#include<stdio.h>
void main()
{
printf("Printing in Parent, only run once\n");
printf("Process ID and parent process ID in parent: %d , %d\n",getpid(),getppid());
fork();
printf("Process ID and parent process ID in (runs in parent and child): %d , %d\n",getpid(),getppid());
while(1);
}
In Child
#include<stdio.h>
void main()
{
printf("Printing in Parent, only run once\n");
printf("Process ID and parent process ID in parent: %d , %d\n",getpid(),getppid());
fork();
printf("Process ID and parent process ID in (runs in parent and child): %d , %d\n",getpid(),getppid());
while(1);
}
Let us understand how the fork works if called multiple time. In this section of code, we will call the fork line by line.
The code:
#include<stdio.h>
void main()
{
printf(" Started from main, Calling forks\n");
fork(); //fork1
printf(" Fork 1 was called.\n");
fork(); //fork2
printf(" Fork 2 was called.\n");
fork(); //fork3
printf(" Fork 3 was called.\n");
fork(); //fork4
printf(" Fork 4 was called.\n");
while(1);
}
Output:

It is indeed confusing. Letโs make a tree and see how it works.

The above tree was made by using the command ps axjf.
Upon running the program, we see that a total of 16 processes have been created. Check the below image for a detailed analysis of how the fork works for that particular code snippet.

Let us look at how the fork function call works when called iteratively.
void main()
{
int i;
for(i=1;i<=3;i++)
{
if(fork()==0)
{
printf("Loop %d - PID:%d\tPPID:%d\n",i,getpid(),getppid() ) ;
}
}
while(1);
}
The output:

Using the PS command:

It can be visualized as the following diagram.

When the fork call is made, the kernel creates a text segment for the child process by setting up a set of per-process page table entries. These entries refer to the same virtual memory page frames that are already in use by the parent process. The text segment is designated as a read-only code segment.
In the case of data, heap, and stack segments, the kernel employs a copy-on-write mechanism. After the fork call, if either the parent or the child process attempts to modify one of these pages that are initially created by the kernel, the kernel intercepts the access and creates a duplicate copy of the page that can be modified. This involves assigning a new page and updating the corresponding page table entry for the child process.
At this point, the parent and child processes can independently modify their respective private copies of the page without affecting each other. The parent’s process page is not copied for the child process; instead, it is shared between the parent and the child upon forking. When a process attempts to modify a shared page, a separate copy of the page is created exclusively for that process. This copy-on-write approach ensures that pages are only duplicated when a process actually writes to them, optimizing memory usage.
By utilizing the fork system call and implementing copy-on-write, the operating system efficiently manages memory resources and allows parent and child processes to safely and independently modify shared and private memory pages as needed.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
An Article by: Yashwanth Naidu Tikkisetty
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
