But the child and parent processes reside on different memory spaces. These memory spaces have same content and whatever operation is performed by one process will not affect the other process.
When the child processes is created; now both the processes will have the same Program Counter (PC), so both of these processes will point to the same next instruction. The files opened by the parent process will be the same for child process.
The child process is exactly the same as its parent but there is difference in the processes ID’s:
- The process ID of the child process is a unique process ID which is different from the ID’s of all other existing processes.
- The Parent process ID will be the same as that of the process ID of child’s parent.
Properties of Child Process
The following are some of the properties that a child process holds:
- The CPU counters and the resource utilizations are initialized to reset to zero.
- When the parent process is terminated, child processes do not receive any signal because PR_SET_PDEATHSIG attribute in prctl() is reset.
- The thread used to call fork() creates the child process. So the address of the child process will be the same as that of parent.
- The file descriptor of parent process is inherited by the child process. For example the offset of the file or status of flags and the I/O attributes will be shared among the file descriptors of child and parent processes. So file descriptor of parent class will refer to same file descriptor of child class.
- The open message queue descriptors of parent process are inherited by the child process. For example if a file descriptor contains a message in parent process the same message will be present in the corresponding file descriptor of child process. So we can say that the flag values of these file descriptors are same.
- Similarly open directory streams will be inherited by the child processes.
- The default Timer slack value of the child class is same as the current timer slack value of parent class.
Properties that are not inherited by Child process
The following are some of the properties that are not inherited by a child process:
- Memory locks
- The pending signal of a child class is empty.
- Process associated record locks (fcntl())
- Asynchronous I/O operations and I/O contents.
- Directory change notifications.
- Timers such as alarm(), setitimer() are not inherited by the child class.
fork() in C
There are no arguments in fork() and the return type of fork() is integer. You have to include the following header files when fork() is used:
#include <sys/types.h>
#include <unistd.h>
When working with fork(), <sys/types.h> can be used for type pid_t for processes ID’s as pid_t is defined in <sys/types.h>.
The header file <unistd.h> is where fork() is defined so you have to include it to your program to use fork().
The return type is defined in <sys/types.h> and fork() call is defined in <unistd.h>. Therefore, you need to include both in your program to use fork() system call.
Syntax of fork()
The syntax of fork() system call in Linux, Ubuntu is as follows:
In the syntax the return type is pid_t. When the child process is successfully created, the PID of the child process is returned in the parent process and 0 will be returned to the child process itself.
If there is any error then -1 is returned to the parent process and the child process is not created.
Example 1: Calling fork()
Consider the following example in which we have used the fork() system call to create a new child process:
#include <sys/types.h>
#include <unistd.h>
int main()
{
fork();
printf("Using fork() system call\n");
return 0;
}
OUTPUT:
sysads@linuxhint $ ./fork
Using fork() system call
Using fork() system call
In this program, we have used fork(), this will create a new child process. When the child process is created, both the parent process and the child process will point to the next instruction (same Program Counter). In this way the remaining instructions or C statements will be executed the total number of process times, that is 2n times, where n is the number of fork() system calls.
So when the fork() call is used one time as above (21 = 2) we will have our output 2 times.
Here when the fork() system call is used, the internal structure will look like:
Consider the following case in which the fork() is used 4 times:
#include <sys/types.h>
#include <unistd.h>
int main()
{
fork();
fork();
fork();
fork();
printf("Using fork() system call\n");
return 0;
}
Output:
sysads@linuxhint $ ./fork
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
Using fork() system call
sysads@linuxhint $
Now the total number of process created are 24 = 16 and we have our print statement executed 16 times.
Example 2: Testing if fork() was successful
In the following example we have used the decision making construct to test the value (int) returned by fork(). And the corresponding messages are displayed:
OUTPUT:
sysads@linuxhint $ ./fork
We are in the parent process
We are in the child process
In the above example we have used the type pid_t which will store the return value of fork(). fork() is called on line:
So the integer value returned by fork() is stored in p and then p is compared to check if our fork() call was successful.
When the fork() call is used and child is created successfully, the id of child process will be returned to parent process and 0 will be returned to the child process.The ID of child process in Parent process will not be the same as the ID of child process in child process itself. In child process the ID of child process will be 0.
With this tutorial you can see how to get started with the fork system call in linux.