fork system call in linux with code examples

Introduction
In computer programming, a fork system call allows a process to create a child process. The child process is an exact copy of the parent process except for a few differences. Understanding the concept and the workings of the fork() system call is important for any programmer working with the Linux operating system.

In this article, we will discuss the fork() system call in Linux and explore code examples to help you better understand how it works.

What is the fork() System Call?

The fork() system call creates a new process by duplicating the parent process, creating a new child process with the same contents as the parent process. The new process is essentially a carbon copy of the parent in terms of code and data.

After the fork() system call, two processes run in separate memory spaces. The parent process continues to execute the code following the fork() system call, while the child process starts executing at the beginning of the same code.

The child process runs independently of the parent process. It has its own process ID (PID), which is different from the parent’s PID. The child process also has its own memory space, which is separate from the parent process. This means that any changes made to the child process’s memory space will not affect the parent process, and vice versa.

Code Example 1: Simple Fork() Example

To better understand the fork() system call, let's look at a simple code example. In this example, we will create a child process that prints a message to the console.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main (void) {
pid_t pid;
/* fork a child process /
pid = fork();
if (pid < 0) {
/
error occurred /
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) {
/
child process /
printf("Hello from Child!
");
return 0;
}
else {
/
parent process /
/
parent will wait for the child to complete */
wait(NULL);
printf("Hello from Parent!
");
exit(0);
}
}

In this example, we first declare a variable 'pid' of the data type 'pid_t', which is used to hold the process ID of the created child process. We then call the fork() system call, which creates a child process. If the fork() system call fails, it returns a negative value. In this case, we print an error message to the console and exit the program.

If the fork() system call succeeds, it returns 0 to the child process, and the process ID of the child to the parent process. In our example, if pid is 0, that indicates the child process, so it prints the message "Hello from child!" to the console.

If pid is not 0, it indicates the parent process, so it waits for the child process to complete its execution using the wait(NULL) function. Once the child process has completed, the parent process prints the message "Hello from Parent!" to the console using printf.

Code Example 2: Forking Multiple Child Processes

In this code example, we will extend the previous example to create multiple child processes using a loop. We will use a Unix command 'ls' to list the files in a directory.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main (void) {
/* loop ten times to create ten child processes /
for (int i=0; i<10; i++) {
pid_t pid;
/
fork a child process /
pid = fork();
if (pid < 0) {
/
error occurred /
fprintf(stderr, "Fork Failed");
return 1;
}
else if (pid == 0) {
/
child process /
printf("[%d] Hello from Child #%d
", getpid(), i);
char
args[] = {"ls", "-l", NULL};
execvp(args[0], args);
exit(0);
}
else {
/* parent process /
/
parent will wait for the child to complete */
wait(NULL);
printf("[%d] Child #%d Complete!
", getpid(), i);
}
}
return 0;
}

In this example, we want to create ten child processes using a loop. We first declare a variable 'i' and set it to 0. We then use a for loop to loop ten times, incrementing 'i' at each iteration.

Inside the loop, we call the fork() system call to create a child process. We then use PID and iteration value to print a message to the console, indicating that the child process has started.

Since we want to use the Unix command 'ls' to list the files in the working directory, we also include code to run this command in the child process using execvp(). This function is used to replace the current process image with a new process image specified by a given command-line argument. In our example, we pass the command 'ls' and the parameter '-l' to execvp().

Once the child process is complete, the parent process, which created the child process, waits for it to complete its execution using the wait(NULL) function.

Finally, the loop repeats again until it has run ten times and all child processes have been created and executed.

Conclusion

This article covered the fork() system call in Linux with code examples. The fork() system call is an important concept for any programmer working with Linux systems. It allows a process to create a new child process, which is a copy of the parent process. The child process runs independently of the parent process and has its own memory space and process ID. Understanding the fork() system call is essential when writing concurrent programs in a Unix-like environment.

let's dive a bit deeper into the fork() system call and its use in Linux programming.

Fork() System Call in Detail

The fork() system call creates a new process by duplicating the current process. The new process is referred to as the child process, and the original process is referred to as the parent process. The child process is an exact copy of the parent process, except for a few differences.

The fork() system call actually returns twice. In the parent process, it returns the process ID of the newly created child process. In the child process, it returns 0. This allows us to distinguish between the parent and child processes and take different actions depending on which process we're in.

Once the fork() system call has been executed, we have two separate processes running independently of each other. Any instances of global or static variables that are modified in one process will not affect the other process.

It's important to note that the child process receives a copy of the parent process's memory space, including the program code, data, and stack memory. However, the two processes then operate on two separate copies of the memory space, and modifications made in one process will not be visible in the other process.

The child process's memory space is created as a "copy-on-write" image of the parent process's memory space. This means that if a child process modifies any data, a new copy of that data is created in the child process's memory space, instead of modifying the parent process's memory space. This helps to conserve system resources and allows the two processes to share common memory until it is modified.

Fork() System Call Example

Let's take a look at a more detailed example of the fork() system call in action. In this example, we will create a child process and output its process ID, then wait for the child process to finish before exiting.

#include <stdio.h>
#include <unistd.h>

int main() {
pid_t pid;

printf("Before fork(): Process ID is %d

", getpid());

pid = fork();

if (pid < 0) {
    fprintf(stderr, "Fork failed

");
return 1;
} else if (pid == 0) {
// we're in the child process
printf("Child process: Process ID is %d
", getpid());
return 0;
} else {
// we're in the parent process
printf("Parent process: Process ID is %d
", getpid());
printf("Child's process ID is %d
", pid);
// wait for the child process to finish
wait(NULL);
printf("Child process finished.
");
return 0;
}
}

This program will output the following:

Before fork(): Process ID is 1234
Parent process: Process ID is 1234
Child's process ID is 5678
Child process: Process ID is 5678
Child process finished.

In this example, the parent process starts by outputting its own process ID. It then calls fork() to create a child process. If fork() returns less than 0, an error has occurred and the program exits with a status of 1.

If fork() returns 0, we're in the child process and output the child process ID before returning 0 to indicate success. In this example, we're not doing anything else in the child process, but this is where you would do any specific work that you need the child process to perform.

If fork() returns a positive integer, we're in the parent process and output the parent process ID and the child process ID. We then call wait() to wait for the child process to finish executing before outputting a message indicating that the child process has finished. We return 0 to indicate success and exit the program.

Conclusion

The fork() system call is a powerful tool in Linux programming, enabling us to create new processes running independently of the current process. By understanding how fork() works, you can create more advanced and powerful programs that run efficiently and effectively.

Popular questions

  1. What is the purpose of the fork() system call in Linux programming?
    Answer: The fork() system call in Linux creates a new process by duplicating the current process. It allows a process to create a new child process, which is an exact copy of the parent process.

  2. What are the differences between the parent process and the child process created by fork()?
    Answer: The child process is an exact copy of the parent process, except for a few differences. The child process has its own process ID, and its memory space is separate from the parent process's memory space.

  3. How does the fork() system call actually return?
    Answer: The fork() system call actually returns twice. It returns the process ID of the newly created child process in the parent process, and it returns 0 in the child process.

  4. What is the purpose of the wait() function in fork() system call code examples?
    Answer: The wait() function in fork() system call code examples is used in the parent process to wait for the child process to finish executing before continuing.

  5. What is the "copy-on-write" mechanism used in the fork() system call?
    Answer: The "copy-on-write" mechanism used in the fork() system call means that any modifications to memory made by one process will not affect the other process. If a child process modifies data, a new copy of that data is created in the child process's memory space, instead of modifying the parent process's memory space.

Tag

"Forks"

As a senior DevOps Engineer, I possess extensive experience in cloud-native technologies. With my knowledge of the latest DevOps tools and technologies, I can assist your organization in growing and thriving. I am passionate about learning about modern technologies on a daily basis. My area of expertise includes, but is not limited to, Linux, Solaris, and Windows Servers, as well as Docker, K8s (AKS), Jenkins, Azure DevOps, AWS, Azure, Git, GitHub, Terraform, Ansible, Prometheus, Grafana, and Bash.

Leave a Reply

Your email address will not be published. Required fields are marked *

Related Posts

Begin typing your search term above and press enter to search. Press ESC to cancel.

Back To Top