fork



The fork() function in C is used for creating a new process in Linux and Unix systems. It allows you to create a child process that runs concurrently with the process that makes the fork() call (which is the parent process). 

Here’s the basic syntax:

#include <unistd.h> 
 pid_t fork(void);

The unistd.h header file, commonly used in C and C++ programming languages, provides access to the POSIX operating system API. Let’s break down its significance:

Definition and Purpose:
  • unistd.h stands for “Unix Standard Header”.
  • It serves as a bridge between your program and the underlying operating system, enabling interaction with system resources and services.
  • The header file contains function prototypes, macros, and constants that allow your program to communicate with the operating system.
Functionality:The interface defined by unistd.h includes various system call wrapper functions and I/O primitives.
Some notable functions and features provided by unistd.h:
fork: Creates a new process by duplicating the address space of the parent process.
pipe: Establishes inter-process communication via a pipe.
read and write: Perform input and output operations.
close: Closes a file descriptor.
dup and dup2: Duplicate file descriptors.
chdir and fchdir: Change the working directory.
getpid: Retrieves the process ID.
link and linkat: Create hard links.
lseek: Reposition the read/write file offset.
pipe2: Creates a pipe with additional options.  And more...............

The fork() function takes no parameters and returns an integer value.
The possible return values are as follows:
  • Negative Value: The creation of a child process was unsuccessful.
  • Zero: Returned to the newly created child process.
  • Positive Value: Returned to the parent or caller. The value contains the process ID (PID) of the newly created child process.
Here’s how it works:
  • The fork() system call creates a new process by duplicating the address space of the original process.
  • The existing process becomes the parent process, and the newly created process is called the child process.
  • The child process inherits the same code, data, and file descriptors from the parent process.
  • After forking, you can use the exec() family of functions to replace the child process’s memory space with a new program.
  • The exec() function loads a new program into the child process, effectively replacing its code and data.
  • This technique allows you to create a new process with different functionality from the parent process.
  • Example:
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
int main() {
    pid_t p = fork();

    if (p < 0) {
        perror("fork failed");
        exit(1);
    } else if (p == 0) {
        printf("Hello from Child! (PID: %d)\n", getpid());
    } else {
        printf("Hello from Parent! (Child PID: %d)\n", p);
    }
    return 0;
}
Output:
Hello from Parent! (Child PID: 12345) 
Hello from Child! (PID: 12346)

In this example, the parent process creates a child process using fork(). The child process runs concurrently with the parent process, and both print their respective messages along with their process IDs.
Remember that the fork() system call creates a child process with an exact copy of the address space, including the program counter, CPU registers, and open files. The child process then continues executing from where the fork() call occurred.

Example 2:
In this program, the parent process creates multiple child processes, and each child process prints its own process ID (PID) along with the parent’s PID.

In this program:
  • The parent process creates num_processes child processes using fork().
  • Each child process prints its own PID and the parent’s PID.
  • The parent process waits for all child processes to finish using wait().
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h> // For fork() and getpid()
#include <sys/wait.h>
int main() {
    int num_processes = 3; // Number of child processes to create
    pid_t child_pid;

    printf("Parent process (PID %d) is creating child processes...\n", getpid());

    for (int i = 0; i < num_processes; ++i) {
        child_pid = fork(); // Create a child process

        if (child_pid == -1) {
            perror("Error creating child process");
            exit(EXIT_FAILURE);
        } else if (child_pid == 0) {
            // Child process
            printf("Child process (PID %d) created by parent (PID %d)\n", getpid(), getppid());
            exit(EXIT_SUCCESS); // Child process exits
        }
    }

    // Parent process waits for all child processes to finish
    for (int i = 0; i < num_processes; ++i) {
        wait(NULL);
    }
    printf("Parent process (PID %d) has finished creating child processes.\n", getpid());
    return 0;
}
output:
Parent process (PID 124449) is creating child processes...
Child process (PID 124450) created by parent (PID 124449)
Child process (PID 124451) created by parent (PID 124449)
Child process (PID 124452) created by parent (PID 124449)
Parent process (PID 124449) has finished creating child processes.

Let's create a simple numerical program that calculates the sum of numbers from 1 to N, where N is provided by the user. We'll use fork() to parallelize the computation by splitting it into two separate processes, each responsible for calculating half of the sum. The parent process will then combine the results from both child processes to get the total sum. Here's the code:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/wait.h>

// Function to calculate the sum of numbers from start to end
int calculate_sum(int start, int end) {
    int sum = 0;
    for (int i = start; i <= end; i++) {
        sum += i;
    }
    return sum;
}

int main() {
    int N;
    
    printf("Enter a number (N<=25): ");
    scanf("%d", &N);
    
    // Fork a child process
    pid_t pid = fork();
    
    if (pid == -1) {
        perror("fork");
        exit(EXIT_FAILURE);
    } else if (pid == 0) {
        // Child process 1
        int sum = calculate_sum(1, N / 2);
        printf("Child 1: Sum of numbers from 1 to %d is %d\n", N / 2, sum);
        exit(sum);
    } else {
        // Parent process
        pid_t pid2 = fork(); // Fork another child process
        
        if (pid2 == -1) {
            perror("fork");
            exit(EXIT_FAILURE);
        } else if (pid2 == 0) {
            // Child process 2
            int sum = calculate_sum(N / 2 + 1, N);
            printf("Child 2: Sum of numbers from %d to %d is %d\n", N / 2 + 1, N, sum);
            exit(sum);
        } else {
            // Parent process
            int status1, status2;
            waitpid(pid, &status1, 0); // Wait for child process 1
            waitpid(pid2, &status2, 0); // Wait for child process 2
            
            int total_sum = WEXITSTATUS(status1) + WEXITSTATUS(status2);
            printf("Parent: Total sum of numbers from 1 to %d is %d\n", N, total_sum);
        }
    }
    
    return 0;
}

Enter a number (N<=25): 20
Child 1: Sum of numbers from 1 to 10 is 55
Child 2: Sum of numbers from 11 to 20 is 155
Parent: Total sum of numbers from 1 to 20 is 210

Note: The exit status is limited to 8 bits.

Comments

Popular posts from this blog

CSL 204 OPERATING SYSTEM LAB KTU IV SEM CSE

FCFS and SJF

Shared Memory Inter-Process Communication ( IPC)