Fork () is a system call in unix which can be used by a process to create a new process. This is a special function which is called once but it returns twice, one for parent process who called the fork () and second for the child process which is created by fork (). Fork () returns process id of the new process in parent process whereas it returns 0 for child process.
Syntax of fork () function call is as follows:
#include <unistd.h>
pid_t fork(void); /* Returns: 0 in child, process ID of child in parent, −1 on error */
Important Points
- Fork () function gets called once but returns twice. It returns 0 for child whereas it returns process id of child to parent.
- Child process gets the copy of all parent’s data.
- Parent process can wait for child process to finish working by calling wait () function.
- All file descriptors that are open in parent process, is duplicated by the child process.
- All the file descriptors file offset are shared by both parent and child. This means any modification of a process will be visible to other process.
- Since file descriptors are shared between parent and child. Hence, some synchronization mechanisms must be used to ensure expected output.
- Any file locks applied by parent is not duplicated by child process.
- Usually fork () is used to create a new process to invoke new program using exec () system call.
- If parent process didn’t wait for child to exit or parent exits before child, then these child processes become child of init process.
Let’s have a look at the sample program to understand it better.
#include <unistd.h>
#include <stdio.h>
#include <stdbool.h>
#include <sys/wait.h>
#include <stdlib.h>
void parent_child_example (bool is_parent_sleep, int var)
{
pid_t pid;
printf ("Before calling fork, var: %d \n", var);
if ((pid = fork ()) < 0)
{
printf ("fork () system call failed \n");
}
else if (pid == 0)
{
if (!is_parent_sleep)
sleep (2);
var++;
printf ("Child process modified var value: %d, parent process: %d, own pid: %d \n",
var, getppid (), getpid ());
exit (10);
}
else
{
if (is_parent_sleep)
sleep (2);
var++;
printf ("parent process modified var value: %d, child process id: %d, own pid: %d \n",
var, pid, getpid ());
/* To ensure child exits first*/
if (!is_parent_sleep)
sleep (3);
printf ("Parent process received returned value of wait %d\n", wait (&pid));
}
}
int main ()
{
printf ("Below example when parent sleeps\n");
parent_child_example (true, 100);
sleep (5);
printf ("Below example when child sleeps\n");
parent_child_example (false, 200);
}
Let’s analyze the output of above program.
Below example when parent sleeps
Before calling fork, var: 100
Child process modified var value: 101, parent process: 907, own pid: 908
parent process modified var value: 101, child process id: 908, own pid: 907
Parent process received returned value of wait 908
Below example when child sleeps
Before calling fork, var: 200
parent process modified var value: 201, child process id: 942, own pid: 907
Child process modified var value: 201, parent process: 907, own pid: 942
Parent process received returned value of wait 942