Go4Expert

Go4Expert (http://www.go4expert.com/)
-   C (http://www.go4expert.com/articles/c-tutorials/)
-   -   Unix System Call Fork() (Create new Processes) (http://www.go4expert.com/articles/unix-fork-create-processes-t26776/)

poornaMoksha 24Sep2011 18:54

Unix System Call Fork() (Create new Processes)
 
The fork() unix API provides mechanism to spawn a new process from an existing process. This function is called once in a program but it returns twice. Once in parent process and once in its child process(the new spawned process becomes the child process).The return value of this function in child is '0' while in parent is the PID(process ID) of the child. The reason of the above stated behavior is since child process can always call function getppid() to get the PID of its parent so the return of fork() in child is zero. On the other hand since there is no way for a parent process to find the PID of its child (also a parent can have various children) so fork() returns the PID of the child process in the parent.

Example



Here is a sample program that will make you understand all the explanation above :

Code:

#include <errno.h>
#include <stdio.h>
#include <sys/wait.h>
#include <stdlib.h>

int main()
{
        pid_t child_pid;
        int status;

        /* now create new process */
        child_pid = fork();

        if (child_pid >= 0) /* fork succeeded */
        {
                if (child_pid == 0) /* fork() returns 0 for the child process */
                {
                        printf("child process!\n");
                        printf("child PID =  %d, parent pid = %d\n", getpid(), getppid());
                        sleep(1); /* consume time */
                        printf("child exists!\n");
                        exit(0);
                }
                else /* parent process */
                {
                        printf("parent process!\n");
                        printf("parent PID =  %d, child pid = %d\n", getpid(), child_pid);
                        wait(&status); /* wait for child to exit, and store child's exit status */
                        printf("Child exit code: %d\n", WEXITSTATUS(status));
                        printf("Parent says bye!\n");
                        exit(0);  /* parent exits */
                }
        }
        else /* failure */
        {
                perror("fork");
                exit(0);
        }
}

In the above program, we fork() a child process and save its PID in 'child_pid' variable. The fork() function returns twice, once in parent and once in child. The program prints all the required information to make you understand the concept of fork() practically.

The output of the above program comes out to be :
parent process!
parent PID = 5019, child pid = 5020
child process!
child PID = 5020, parent pid = 5019
child exists!
Child exit code: 0
Parent says bye!

Some Useful Information



It is to be noted that child gets a copy of the parents memory. ie, it gets copy of the parents data space, heap and stack. The parent and child do not share these memories any more. They share only the text segment.

Following example makes the above statement clear :

Code:

#include <unistd.h>   
#include <sys/types.h> 
#include <errno.h>   
#include <stdio.h>     
#include <sys/wait.h> 
#include <stdlib.h>   
 
int global; /* In BSS segement, will automatically be assigned '0'*/

int main()
{
        pid_t child_pid;
        int status;   
        int local = 0;       
        /* now create new process */
        child_pid = fork();

        if (child_pid >= 0) /* fork succeeded */
        {
                if (child_pid == 0) /* fork() returns 0 for the child process */
                {
                        printf("child process!\n");
                        local++;
                        global++;

                        printf("child PID =  %d, parent pid = %d\n", getpid(), getppid());
                        printf("\n child's local = %d, child's global = %d\n",local,global);
                        sleep(1); /* consume time */
                        printf("child exists!\n");   
                        exit(0);
                }
                else /* parent process */
                {
                        printf("parent process!\n");
                        printf("parent PID =  %d, child pid = %d\n", getpid(), child_pid);
                        wait(&status); /* wait for child to exit, and store child's exit status */
                        printf("Child exit code: %d\n", WEXITSTATUS(status));
                        printf("\n Parent's local = %d, parent's  global = %d\n",local,global);
                        printf("Parent says bye!\n");           
                        exit(0);  /* parent exits */     
                }
        }
        else /* failure */
        {
        perror("fork");
        exit(0);
        }
}

In the above program, we introduced two variables : 'local' and 'global'. The variable 'local' is on stack while the variable 'global' is in the data segment. Now, the program increments these two variables in child process while no increment to these is done in the parent process. Here is the output :
parent process!
parent PID = 5082, child pid = 5083
child process!
child PID = 5083, parent pid = 5082

child's local = 1, child's global = 1
child exists!
Child exit code: 0

Parent's local = 0, parent's global = 0
Parent says bye!
Here we see that the child's variables have incremented values (local = 1, global = 1) while parent's variables have the original value (local = 0, global = 0). So this verifies the statement above that said that both child and parent have different set of stack, heap and global memory segments.

The point to be noted is that current implementations do not strictly perform a complete copy of parents data, stack and heap memory because of a mechanism known as 'Copy-on-write' (COW). These regions are shared by both the child and parent until and unless one of them try to write on any of these memory regions. Its at the first write by either parent or child is when the copy of parents memory regions is made available for child for future usage. Hence the term 'Copy-on-Write'.

Another point is that whether the child starts executing first or the parent, this is decided by the kernel's process scheduling mechanisms. So In case the child and parent are reading-writing from shared file or other shared source then always use some process synchronization techniques (like semaphore) to make sure that read-writes are occurring as desired.

Conclusion



The fork() function is an extremely useful API for creating child processes from a process. The original process becomes parent while the fork(ed) processes become the child. Every child shares only the text segment of memory with parent while has its own copy of stack, heap and global segments.


All times are GMT +5.5. The time now is 10:04.