Lesson 02intermediateProcesses

Process Creation with fork()

Introduction to process creation using fork(). Demonstrates parent/child relationships, zombie processes, the classic fork-in-a-loop mistake, the fix with wait/exit, and process timing with gettimeofday.

forkwaitzombieprocesspid
1

POSIX Includes Reference

A reference file listing the key POSIX headers used throughout the course: unistd.h, sys/types.h, sys/wait.h, and more.

00-some-includes.c105 lines
2

First fork()

The simplest fork example — creating a child process and printing PIDs from both parent and child.

01-basic-forking.c80 lines
/*
 * 01-basic-forking.c — Your first fork() example
 *
 * Demonstrates: Creating a child process with fork()
 * Key concepts: fork() return values, PID, parent vs child execution paths
 * Compile: gcc -o basic_fork 01-basic-forking.c
 * Run:     ./basic_fork
 *
 * NOTE: This code runs on Linux/macOS only — Windows does not support fork().
 */

#include <stdio.h>
#include <stdlib.h>    // for exit(), EXIT_FAILURE
#include <unistd.h>    // for fork(), getpid()
#include <sys/wait.h>  // for wait()

/*
 * fork() creates a new process by duplicating the calling process.
 * After fork(), TWO processes run the same code from the same point.
 *
 * Return values:
 *   Negative : fork failed (system out of resources)
 *   Zero (0) : you are in the CHILD process
 *   Positive : you are in the PARENT process, value = child's PID
 *
 * Tip: man pages are your best friend — https://man7.org/linux/man-pages/
 */


void check_valid_process(pid_t status);

int main()
{

    printf("\n");
    printf("========================================\n");
    printf("  Your First fork() — Parent vs Child\n");
    printf("========================================\n\n");

    pid_t pid = fork(); // fork() creates a new process

    if (pid < 0)
    {
        // I RECOMMEND TO CREATE A FUNCTION FOR ALL FUTURE ERROR HANDLING
        // Fork failed
        perror("fork failed");
        return 1;
    }
    else if (pid == 0)
    {
        // Child process
        printf("[Child]  I am the child process!  My PID: %d, my parent's PID: %d\n", getpid(), getppid());
        return 0;
    }
    else
    {
        // Parent process
        printf("[Parent] I am the parent process! My PID: %d, fork() returned child PID: %d\n", getpid(), pid);
        // NOTE: No wait() here on purpose! The parent exits without reaping the child.
        // This creates a zombie process — the next example (01.5-forking-zombies.c) explains why.
        // The fix is shown in 03-basic-fork-thefix.c.
        return 0;
    }

    // This code is unreachable — both branches return above.
    // The wait() call below never executes, which is the point:
    // students should notice the missing wait() and understand its consequences.
    wait(NULL);
    return 0;
}

// example check if the process is valid,else we exit the program
void check_valid_process(pid_t status)
{
    if (status < 0)
    {
        perror("Process creation failed");
        exit(EXIT_FAILURE);
    }
}
Expected Outputclick Run to execute live
========================================
  Your First fork() — Parent vs Child
========================================

[Parent] I am the parent process! My PID: 377904, fork() returned child PID: 377905

========================================
  Your First fork() — Parent vs Child
========================================

[Child]  I am the child process!  My PID: 377905, my parent's PID: 377904
3

Zombie Processes

What happens when a child exits before the parent calls wait — creating and observing zombie processes, with an explanation of orphan adoption by init.

01.5-forking-zombies.c39 lines
/*
 * 01.5-forking-zombies.c — Understanding zombie and orphan processes
 *
 * Demonstrates: What happens when parent doesn't wait() on children
 * Key concepts: Zombie processes, orphan adoption by init (PID 1), process table cleanup
 * Compile: gcc -o zombies 01.5-forking-zombies.c
 * Run:     ./zombies   (then check with: ps aux | grep Z)
 */

#include <stdio.h>

/*
In Unix-like operating systems (including Linux), the init process (with PID 1) plays a crucial role in process management. When a child process is left "orphaned" (because its parent process has terminated without waiting for it), the init process automatically adopts it. Here’s how this relates to zombies and waiting on child processes:

Understanding Zombies and Orphan Processes
Zombie Process:

A zombie process is a child process that has completed execution but remains in the process table because its parent hasn’t called wait() to read its exit status.
This process remains as a "zombie" until the parent either reaps it by calling wait() or the parent itself terminates, allowing the operating system to handle it.
Orphaned Process and init Adoption:

When a parent process terminates without waiting on its child processes, those children become "orphans."
The operating system automatically assigns these orphan processes to the init process (PID 1).
The init process is designed to continuously wait on all its children, so when it adopts an orphan process, it will eventually reap it, cleaning up any zombie state and freeing resources.
Automatic Cleanup by init:

This behavior allows zombie processes to be cleared even if the original parent process doesn’t explicitly call wait().
In effect, simply terminating the parent process will result in any zombie child processes being adopted and cleaned up by init.


Example: Creating and Observing Orphan and Zombie Processes
You can create zombie processes and let them be automatically cleaned up by init by ending the parent process without waiting on its children. Here’s an example:
*/


/// AT THIS POINT USE THE FOLLOWING:
// Use ps aux | grep Z
// to see the zombie process
4

Fork-in-Loop Mistake

The classic bug: calling fork() inside a loop without exiting the child, causing exponential process creation.

02-basic-fork-mistake.c65 lines
/*
 * 02-basic-fork-mistake.c — The classic fork-in-a-loop bug
 *
 * Demonstrates: What goes WRONG when you fork() inside a loop without exiting
 * Key concepts: Exponential process creation, fork bomb pattern
 * Compile: gcc -o fork_mistake 02-basic-fork-mistake.c
 * Run:     ./fork_mistake
 *
 * BUG: The child process does NOT exit after printing — it continues the loop
 *      and calls fork() again! With 5 iterations, you get ~2^5 = 32 processes,
 *      not 5. See 03-basic-fork-thefix.c for the corrected version.
 */

#include <stdio.h>
#include <stdlib.h>    // for exit(), EXIT_FAILURE
#include <unistd.h>    // for fork(), getpid()

void check_valid_process(pid_t status);
int main()
{

    printf("\n");
    printf("========================================\n");
    printf("  BUG: fork() in a loop without exit()\n");
    printf("========================================\n");
    printf("  Watch: children don't exit, so they\n");
    printf("  loop again and fork MORE children!\n\n");

    for (int i = 0; i < 5; i++)
    {
        pid_t pid = fork(); // fork() creates a new process

        if (pid < 0)
        {
            // I RECOMMEND TO CREATE A FUNCTION FOR ALL FUTURE ERROR HANDLING
            // Fork failed
            perror("fork failed");
            return 1;
        }
        else if (pid == 0)
        {
            // BUG: Child prints but does NOT exit — it loops and forks again!
            printf("[Child  PID %d] iteration %d — BUG: I will keep looping and forking more children!\n", getpid(), i);
        }
        else
        {
            // Parent process
            printf("[Parent PID %d] iteration %d — created child PID %d\n", getpid(), i, pid);
        }
    }

  

    return 0;
}

// example check if the process is valid,else we exit the program
void check_valid_process(pid_t status)
{
    if (status < 0)
    {
        perror("Failed To open procceses");
        exit(EXIT_FAILURE);
    }
}
Expected Outputclick Run to execute live
========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Parent PID 377921] iteration 1 — created child PID 377923
[Parent PID 377921] iteration 2 — created child PID 377925
[Parent PID 377921] iteration 3 — created child PID 377929
[Parent PID 377921] iteration 4 — created child PID 377935

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Child  PID 377923] iteration 1 — BUG: I will keep looping and forking more children!
[Parent PID 377923] iteration 2 — created child PID 377927
[Parent PID 377923] iteration 3 — created child PID 377930
[Parent PID 377923] iteration 4 — created child PID 377937

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Parent PID 377922] iteration 1 — created child PID 377924
[Parent PID 377922] iteration 2 — created child PID 377926
[Parent PID 377922] iteration 3 — created child PID 377931
[Parent PID 377922] iteration 4 — created child PID 377938

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Parent PID 377921] iteration 1 — created child PID 377923
[Parent PID 377921] iteration 2 — created child PID 377925
[Child  PID 377929] iteration 3 — BUG: I will keep looping and forking more children!
[Parent PID 377929] iteration 4 — created child PID 377936

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Parent PID 377921] iteration 1 — created child PID 377923
[Parent PID 377921] iteration 2 — created child PID 377925
[Child  PID 377929] iteration 3 — BUG: I will keep looping and forking more children!
[Child  PID 377936] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Parent PID 377921] iteration 1 — created child PID 377923
[Child  PID 377925] iteration 2 — BUG: I will keep looping and forking more children!
[Child  PID 377932] iteration 3 — BUG: I will keep looping and forking more children!
[Parent PID 377932] iteration 4 — created child PID 377943

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Parent PID 377922] iteration 1 — created child PID 377924
[Child  PID 377926] iteration 2 — BUG: I will keep looping and forking more children!
[Parent PID 377926] iteration 3 — created child PID 377934
[Parent PID 377926] iteration 4 — created child PID 377944

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Parent PID 377922] iteration 1 — created child PID 377924
[Parent PID 377922] iteration 2 — created child PID 377926
[Child  PID 377931] iteration 3 — BUG: I will keep looping and forking more children!
[Parent PID 377931] iteration 4 — created child PID 377941

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Child  PID 377924] iteration 1 — BUG: I will keep looping and forking more children!
[Child  PID 377928] iteration 2 — BUG: I will keep looping and forking more children!
[Parent PID 377928] iteration 3 — created child PID 377939
[Parent PID 377928] iteration 4 — created child PID 377945

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Parent PID 377921] iteration 1 — created child PID 377923
[Child  PID 377925] iteration 2 — BUG: I will keep looping and forking more children!
[Parent PID 377925] iteration 3 — created child PID 377932
[Parent PID 377925] iteration 4 — created child PID 377940

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Child  PID 377924] iteration 1 — BUG: I will keep looping and forking more children!
[Parent PID 377924] iteration 2 — created child PID 377928
[Child  PID 377933] iteration 3 — BUG: I will keep looping and forking more children!
[Parent PID 377933] iteration 4 — created child PID 377948

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Child  PID 377924] iteration 1 — BUG: I will keep looping and forking more children!
[Parent PID 377924] iteration 2 — created child PID 377928
[Parent PID 377924] iteration 3 — created child PID 377933
[Parent PID 377924] iteration 4 — created child PID 377946

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Parent PID 377922] iteration 1 — created child PID 377924
[Child  PID 377926] iteration 2 — BUG: I will keep looping and forking more children!
[Child  PID 377934] iteration 3 — BUG: I will keep looping and forking more children!
[Parent PID 377934] iteration 4 — created child PID 377947

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Parent PID 377922] iteration 1 — created child PID 377924
[Parent PID 377922] iteration 2 — created child PID 377926
[Parent PID 377922] iteration 3 — created child PID 377931
[Child  PID 377938] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Child  PID 377923] iteration 1 — BUG: I will keep looping and forking more children!
[Parent PID 377923] iteration 2 — created child PID 377927
[Parent PID 377923] iteration 3 — created child PID 377930
[Child  PID 377937] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Child  PID 377924] iteration 1 — BUG: I will keep looping and forking more children!
[Parent PID 377924] iteration 2 — created child PID 377928
[Parent PID 377924] iteration 3 — created child PID 377933
[Child  PID 377946] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Parent PID 377922] iteration 1 — created child PID 377924
[Parent PID 377922] iteration 2 — created child PID 377926
[Child  PID 377931] iteration 3 — BUG: I will keep looping and forking more children!
[Child  PID 377941] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Parent PID 377921] iteration 1 — created child PID 377923
[Child  PID 377925] iteration 2 — BUG: I will keep looping and forking more children!
[Child  PID 377932] iteration 3 — BUG: I will keep looping and forking more children!
[Child  PID 377943] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Parent PID 377921] iteration 1 — created child PID 377923
[Parent PID 377921] iteration 2 — created child PID 377925
[Parent PID 377921] iteration 3 — created child PID 377929
[Child  PID 377935] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Parent PID 377922] iteration 1 — created child PID 377924
[Child  PID 377926] iteration 2 — BUG: I will keep looping and forking more children!
[Child  PID 377934] iteration 3 — BUG: I will keep looping and forking more children!
[Child  PID 377947] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Child  PID 377923] iteration 1 — BUG: I will keep looping and forking more children!
[Parent PID 377923] iteration 2 — created child PID 377927
[Child  PID 377930] iteration 3 — BUG: I will keep looping and forking more children!
[Parent PID 377930] iteration 4 — created child PID 377942

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Parent PID 377921] iteration 1 — created child PID 377923
[Child  PID 377925] iteration 2 — BUG: I will keep looping and forking more children!
[Parent PID 377925] iteration 3 — created child PID 377932
[Child  PID 377940] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Child  PID 377924] iteration 1 — BUG: I will keep looping and forking more children!
[Child  PID 377928] iteration 2 — BUG: I will keep looping and forking more children!
[Child  PID 377939] iteration 3 — BUG: I will keep looping and forking more children!
[Parent PID 377939] iteration 4 — created child PID 377950

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Child  PID 377924] iteration 1 — BUG: I will keep looping and forking more children!
[Child  PID 377928] iteration 2 — BUG: I will keep looping and forking more children!
[Child  PID 377939] iteration 3 — BUG: I will keep looping and forking more children!
[Child  PID 377950] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Child  PID 377924] iteration 1 — BUG: I will keep looping and forking more children!
[Parent PID 377924] iteration 2 — created child PID 377928
[Child  PID 377933] iteration 3 — BUG: I will keep looping and forking more children!
[Child  PID 377948] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Child  PID 377923] iteration 1 — BUG: I will keep looping and forking more children!
[Child  PID 377927] iteration 2 — BUG: I will keep looping and forking more children!
[Parent PID 377927] iteration 3 — created child PID 377949
[Parent PID 377927] iteration 4 — created child PID 377951

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Child  PID 377923] iteration 1 — BUG: I will keep looping and forking more children!
[Child  PID 377927] iteration 2 — BUG: I will keep looping and forking more children!
[Child  PID 377949] iteration 3 — BUG: I will keep looping and forking more children!
[Parent PID 377949] iteration 4 — created child PID 377952

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Child  PID 377924] iteration 1 — BUG: I will keep looping and forking more children!
[Child  PID 377928] iteration 2 — BUG: I will keep looping and forking more children!
[Parent PID 377928] iteration 3 — created child PID 377939
[Child  PID 377945] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Child  PID 377923] iteration 1 — BUG: I will keep looping and forking more children!
[Child  PID 377927] iteration 2 — BUG: I will keep looping and forking more children!
[Child  PID 377949] iteration 3 — BUG: I will keep looping and forking more children!
[Child  PID 377952] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Child  PID 377923] iteration 1 — BUG: I will keep looping and forking more children!
[Parent PID 377923] iteration 2 — created child PID 377927
[Child  PID 377930] iteration 3 — BUG: I will keep looping and forking more children!
[Child  PID 377942] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Parent PID 377921] iteration 0 — created child PID 377922
[Child  PID 377923] iteration 1 — BUG: I will keep looping and forking more children!
[Child  PID 377927] iteration 2 — BUG: I will keep looping and forking more children!
[Parent PID 377927] iteration 3 — created child PID 377949
[Child  PID 377951] iteration 4 — BUG: I will keep looping and forking more children!

========================================
  BUG: fork() in a loop without exit()
========================================
  Watch: children don't exit, so they
  loop again and fork MORE children!

[Child  PID 377922] iteration 0 — BUG: I will keep looping and forking more children!
[Parent PID 377922] iteration 1 — created child PID 377924
[Child  PID 377926] iteration 2 — BUG: I will keep looping and forking more children!
[Parent PID 377926] iteration 3 — created child PID 377934
[Child  PID 377944] iteration 4 — BUG: I will keep looping and forking more children!
5

The Fix: wait + exit

Fixing the fork-in-loop mistake by having the child call exit() and the parent call wait(), ensuring proper process lifecycle.

03-basic-fork-thefix.c71 lines
/*
 * 03-basic-fork-thefix.c — Correct way to fork in a loop
 *
 * Demonstrates: Fixing the fork-in-a-loop bug from 02-basic-fork-mistake.c
 * Key concepts: Child must exit() after its work, parent must wait() for each child
 * Compile: gcc -o fork_fix 03-basic-fork-thefix.c
 * Run:     ./fork_fix
 *
 * Two fixes applied:
 *   1. Child calls exit(0) so it doesn't continue the loop
 *   2. Parent calls wait(NULL) to reap each child before forking the next
 */

#include <stdio.h>
#include <stdlib.h>    // for exit(), EXIT_FAILURE
#include <unistd.h>    // for fork(), getpid()
#include <sys/wait.h>  // for wait()

void check_valid_process(pid_t status);


int main() {
    printf("\n");
    printf("========================================\n");
    printf("  FIX: fork() in a loop (with exit+wait)\n");
    printf("========================================\n");
    printf("  Fixes: child calls exit(), parent\n");
    printf("  calls wait() before next fork.\n");

    const int RUNS = 5;
    pid_t status;
    for (int i = 0; i < RUNS; i++) {
        printf("\n--- Run %d ---\n", i + 1);
        
        pid_t pid = fork();  // fork() creates a new process

        if (pid < 0) {
            // Fork failed
            perror("fork failed");
            return 1;
        } else if (pid == 0) {
            // Child process
            printf("[Child  PID %d] Hello from child (run %d)! I will exit(0) now.\n", getpid(), i + 1);
            exit(0);  // FIX #1: Child exits here — won't continue the for-loop
        } else {
            // Parent process
            printf("[Parent PID %d] Created child PID %d. Waiting for it...\n", getpid(), pid);
            // FIX #2: Parent waits for child to finish before next iteration
            // wait(NULL) returns child PID on success, -1 on failure
            status = wait(NULL);
            if (status < 0) {
                perror("Failed to wait for child process");
                exit(EXIT_FAILURE);
            }
            else {
                printf("[Parent PID %d] wait() returned %d — child has been reaped.\n", getpid(), status);
            }
        }
    }

    return 0;
}

// Example function to check if the process is valid; exits if not
void check_valid_process(pid_t status) {
    if (status < 0) {
        perror("Failed to create process");
        exit(EXIT_FAILURE);
    }
}
Expected Outputclick Run to execute live
========================================
  FIX: fork() in a loop (with exit+wait)
========================================
  Fixes: child calls exit(), parent
  calls wait() before next fork.

--- Run 1 ---
[Child  PID 377963] Hello from child (run 1)! I will exit(0) now.

========================================
  FIX: fork() in a loop (with exit+wait)
========================================
  Fixes: child calls exit(), parent
  calls wait() before next fork.

--- Run 1 ---
[Parent PID 377962] Created child PID 377963. Waiting for it...
[Parent PID 377962] wait() returned 377963 — child has been reaped.

--- Run 2 ---
[Child  PID 377964] Hello from child (run 2)! I will exit(0) now.

========================================
  FIX: fork() in a loop (with exit+wait)
========================================
  Fixes: child calls exit(), parent
  calls wait() before next fork.

--- Run 1 ---
[Parent PID 377962] Created child PID 377963. Waiting for it...
[Parent PID 377962] wait() returned 377963 — child has been reaped.

--- Run 2 ---
[Parent PID 377962] Created child PID 377964. Waiting for it...
[Parent PID 377962] wait() returned 377964 — child has been reaped.

--- Run 3 ---
[Child  PID 377965] Hello from child (run 3)! I will exit(0) now.

========================================
  FIX: fork() in a loop (with exit+wait)
========================================
  Fixes: child calls exit(), parent
  calls wait() before next fork.

--- Run 1 ---
[Parent PID 377962] Created child PID 377963. Waiting for it...
[Parent PID 377962] wait() returned 377963 — child has been reaped.

--- Run 2 ---
[Parent PID 377962] Created child PID 377964. Waiting for it...
[Parent PID 377962] wait() returned 377964 — child has been reaped.

--- Run 3 ---
[Parent PID 377962] Created child PID 377965. Waiting for it...
[Parent PID 377962] wait() returned 377965 — child has been reaped.

--- Run 4 ---
[Child  PID 377966] Hello from child (run 4)! I will exit(0) now.

========================================
  FIX: fork() in a loop (with exit+wait)
========================================
  Fixes: child calls exit(), parent
  calls wait() before next fork.

--- Run 1 ---
[Parent PID 377962] Created child PID 377963. Waiting for it...
[Parent PID 377962] wait() returned 377963 — child has been reaped.

--- Run 2 ---
[Parent PID 377962] Created child PID 377964. Waiting for it...
[Parent PID 377962] wait() returned 377964 — child has been reaped.

--- Run 3 ---
[Parent PID 377962] Created child PID 377965. Waiting for it...
[Parent PID 377962] wait() returned 377965 — child has been reaped.

--- Run 4 ---
[Parent PID 377962] Created child PID 377966. Waiting for it...
[Parent PID 377962] wait() returned 377966 — child has been reaped.

--- Run 5 ---
[Child  PID 377967] Hello from child (run 5)! I will exit(0) now.

========================================
  FIX: fork() in a loop (with exit+wait)
========================================
  Fixes: child calls exit(), parent
  calls wait() before next fork.

--- Run 1 ---
[Parent PID 377962] Created child PID 377963. Waiting for it...
[Parent PID 377962] wait() returned 377963 — child has been reaped.

--- Run 2 ---
[Parent PID 377962] Created child PID 377964. Waiting for it...
[Parent PID 377962] wait() returned 377964 — child has been reaped.

--- Run 3 ---
[Parent PID 377962] Created child PID 377965. Waiting for it...
[Parent PID 377962] wait() returned 377965 — child has been reaped.

--- Run 4 ---
[Parent PID 377962] Created child PID 377966. Waiting for it...
[Parent PID 377962] wait() returned 377966 — child has been reaped.

--- Run 5 ---
[Parent PID 377962] Created child PID 377967. Waiting for it...
[Parent PID 377962] wait() returned 377967 — child has been reaped.
6

Timing with gettimeofday

Using gettimeofday to measure elapsed time across parent and child processes.

04-forks-gettimeday.c65 lines
/*
 * 04-forks-gettimeday.c — Measuring parallel execution time with fork
 *
 * Demonstrates: Using gettimeofday() to time forked processes
 * Key concepts: Both parent and child run simultaneously — total time is ~2s, not ~4s
 * Compile: gcc -o fork_time 04-forks-gettimeday.c
 * Run:     ./fork_time
 */

#include <stdio.h>
#include <stdlib.h>
#include <sys/time.h>  // for gettimeofday(), struct timeval
#include <sys/wait.h>  // for wait()
#include <unistd.h>    // for fork(), sleep()

void perform_task() {
    // Simulate a task by sleeping for 2 seconds
    sleep(2);
}

int main() {
    struct timeval start, end;
    pid_t pid;
    double elapsed_time;

    printf("\n");
    printf("========================================\n");
    printf("  Parallel Execution with fork()\n");
    printf("========================================\n");
    printf("  Each process sleeps 2 seconds.\n");
    printf("  Sequential: ~4s. Parallel: ~2s.\n\n");

    gettimeofday(&start, NULL); // Get the start time

    pid = fork(); // Create a new process

    if (pid == -1) {
        // If fork() returns -1, an error occurred
        perror("Failed to fork");
        return 1;
    } else if (pid == 0) {
        // Child process
        perform_task();
        printf("[Child  PID %d] Task completed (slept 2 seconds)\n", getpid());
    } else {
        // Parent process
        perform_task();
        printf("[Parent PID %d] Task completed (slept 2 seconds). Waiting for child...\n", getpid());

        // Wait for the child to finish
        wait(NULL);
    }

    gettimeofday(&end, NULL); // Get the end time

    // Calculate the elapsed time in microseconds, then convert to seconds
    elapsed_time = (end.tv_sec - start.tv_sec) * 1000000.0; // sec to us
    elapsed_time += (end.tv_usec - start.tv_usec); // us
    elapsed_time /= 1000000.0; // convert back to seconds

    printf("[PID %d] Total elapsed time: %.2f seconds (both tasks ran in parallel!)\n", getpid(), elapsed_time);

    return 0;
}
Expected Outputclick Run to execute live
========================================
  Parallel Execution with fork()
========================================
  Each process sleeps 2 seconds.
  Sequential: ~4s. Parallel: ~2s.

[Child  PID 377978] Task completed (slept 2 seconds)
[PID 377978] Total elapsed time: 2.00 seconds (both tasks ran in parallel!)

========================================
  Parallel Execution with fork()
========================================
  Each process sleeps 2 seconds.
  Sequential: ~4s. Parallel: ~2s.

[Parent PID 377977] Task completed (slept 2 seconds). Waiting for child...
[PID 377977] Total elapsed time: 2.00 seconds (both tasks ran in parallel!)

Open Full Terminal

Get a Linux terminal with all 6 files from this lesson pre-loaded. Compile, run, and experiment freely.