Quiz 2

Process Management — Processes, PCB, States & Context Switch

1955 words
10 min read
Python Week 1: the first filter for runtime behavior
Visual companion
Python
Type and operator map

Python Week 1: the first filter for runtime behavior

View
Revision summary

What this note is really saying

Short form

# Process Management — Processes, PCB, States & Context Switch > **Learning Objectives:** After this topic, you will be able to explain what a process is, describe its states and transitions, create processes using fork/exec, and trace context switch behavior. ## 🎯 Learning Objectives - Define a process and differe...

Process Management — Processes, PCB, States & Context Switch

Learning Objectives: After this topic, you will be able to explain what a process is, describe its states and transitions, create processes using fork/exec, and trace context switch behavior.

🎯 Learning Objectives

  • Define a process and differentiate it from a program
  • Identify all process states and valid transitions between them
  • Describe the contents and purpose of a Process Control Block (PCB)
  • Explain context switching and calculate its overhead
  • Write programs using fork(), exec(), wait(), and exit() system calls
  • Distinguish between zombie and orphan processes

📋 Prerequisites

  • BSCS3031 (CSD): Basic understanding of CPU, memory, registers
  • BSCS3005 (C Programming): System calls, process creation in C

1. What is a Process?

1.1 Intuition

A program is a passive entity — a file on disk containing instructions. A process is an active entity — the program in execution with all its associated resources (memory, CPU registers, open files). Think of a program as a recipe book and a process as the actual cooking happening in the kitchen.

1.2 Formal Definition

A process is an instance of a program in execution, characterized by:
  • Text section: program code (instructions)
  • Data section: global/static variables
  • Heap: dynamically allocated memory
  • Stack: function call frames, local variables
  • Registers: Program Counter (PC), Stack Pointer (SP), CPU registers
  • OS resources: open file descriptors, network connections, etc.
pseudo
┌─────────────────────────────────┐
│          Process Memory          │
├─────────────────────────────────┤
│          Stack (LIFO)           │  ← grows downward
├─────────────────────────────────┤
│              ↓                   │
│         (free memory)            │
│              ↑                   │
├─────────────────────────────────┤
│          Heap                    │  ← grows upward
├─────────────────────────────────┤
│      Data (BSS + initialized)   │
├─────────────────────────────────┤
│      Text (Program Code)        │
└─────────────────────────────────┘

1.3 Program vs Process

AspectProgramProcess
NaturePassive (file on disk)Active (in memory + CPU)
LifetimePermanent (until deleted)Temporary (from creation to termination)
ResourcesZeroCPU, memory, files, I/O
IdentifierFilenamePID (Process ID)
Multiple instancesOne fileMany processes possible

1.4 Process States

A process transitions through several states during its lifecycle: (Diagram) State descriptions:
StateDescription
NewProcess is being created (PCB allocated, not yet ready)
ReadyProcess is in main memory, waiting for CPU allocation
RunningProcess is currently executing on the CPU
Waiting (Blocked)Process is waiting for I/O or an event to complete
TerminatedProcess has finished execution, PCB retained temporarily

1.5 Process Control Block (PCB)

The PCB is a data structure in the kernel that stores all information about a process. Created when the process is created, it is the only persistent record of the process. (Diagram) PCB Fields:
FieldDescription
PIDUnique process identifier
Process StateCurrent state (new, ready, running, waiting, terminated)
Program CounterAddress of next instruction to execute
CPU RegistersSaved register values (for context switch)
Memory LimitsBase and limit registers, page tables
Open FilesList of file descriptors
CPU Scheduling InfoPriority, time quantum, scheduling class
Accounting InfoCPU time used, process ownership
I/O StatusList of I/O devices allocated to process

2. Context Switching

2.1 Intuition

A context switch is the mechanism by which the OS pauses one process and resumes another on the CPU. The kernel saves the state (registers, PC, SP) of the current process into its PCB and loads the saved state of the next process. This happens tens to hundreds of times per second.

2.2 Context Switch Flow

(Diagram)

2.3 Context Switch Overhead

Context switching is pure overhead — the CPU does no useful work during the switch.
ComponentTime (typical)
Save registers (A)~0.5 - 2 μs
Scheduler decision~0.5 - 5 μs
TLB flush + cache miss~10 - 100 μs
Load registers (B)~0.5 - 2 μs
Total~11 - 109 μs
Example: If a system does 1000 context switches/second with 50 μs each, the overhead is:
Overhead=1000×50×106=0.05 seconds5% of CPU time\text{Overhead} = 1000 \times 50 \times 10^{-6} = 0.05 \text{ seconds} \approx 5\% \text{ of CPU time}

3. Process Creation

3.1 fork() System Call

The fork() system call creates a new process (child) as an almost exact copy of the calling process (parent). (Diagram) Key properties of fork():
  1. Child gets a copy of parent's address space (not shared — copy-on-write in modern OS)
  2. Both processes execute the next instruction after fork()
  3. Return value differs: 0 in child, child's PID in parent, -1 on error
  4. Child inherits: open files, signal handlers, environment, working directory

3.2 exec() Family

The exec() system call replaces the current process image with a new program.
FunctionDescription
execl()List of arguments (null-terminated)
execv()Array of arguments
execlp()Like execl, but searches PATH
execvp()Like execv, but searches PATH

3.3 wait() and exit()

  • wait(): Parent blocks until child terminates. Returns child's PID.
  • waitpid(pid, &status, options): Wait for a specific child.
  • exit(status): Terminates process, returns status to parent.

3.4 Zombie and Orphan Processes

(Diagram)
Process TypeDescription
ZombieChild exited, parent hasn't called wait() yet. PCB retained (memory leak if parent never calls wait).
OrphanParent exited before child. Child adopted by init (PID 1), which automatically calls wait().

4. Worked Examples

Example 1: Simple fork()

c
#include <stdio.h>
#include <unistd.h>
int main() {
    pid_t pid = fork();
    if (pid == 0) {
        printf("CHILD: My PID = %d, Parent PID = %d\n", getpid(), getppid());
    } else if (pid > 0) {
        printf("PARENT: My PID = %d, Child PID = %d\n", getpid(), pid);
    } else {
        perror("fork failed");
    }
    return 0;
}
Output (order may vary):
pseudo
PARENT: My PID = 1000, Child PID = 1001
CHILD: My PID = 1001, Parent PID = 1000
Tracing:
StepActionProcesses
1Program starts as single processP(PID=1000)
2fork() calledP(1000) + C(1001) created
3aParent: pid > 0, prints messageP(1000) running
3bChild: pid == 0, prints messageC(1001) running
4Both processes return 0 and exitBoth terminate

Example 2: fork() with wait()

c
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
    pid_t pid = fork();
    if (pid == 0) {
        // Child process
        printf("Child starts work...\n");
        sleep(2);  // Simulate work
        printf("Child finishes work.\n");
        return 42;  // Exit with status
    } else {
        // Parent process
        int status;
        printf("Parent waiting for child...\n");
        wait(&status);  // Block until child exits
        printf("Child exited with status: %d\n", WEXITSTATUS(status));
    }
    return 0;
}
Tracing:
TimeParent StateChild StateOutput
0Running----
0.1fork() doneReady"Parent waiting..."
0.2Blocked (wait)Running"Child starts work..."
2.2Blocked (wait)Running--
2.3Blocked (wait)Terminated"Child finishes work."
2.4Ready----
2.5Running--"Child exited with status: 42"

Example 3: Zombie Process

c
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>
int main() {
    pid_t pid = fork();
    if (pid == 0) {
        printf("Child (PID: %d) exiting now...\n", getpid());
        _exit(0);  // Child exits immediately
    } else {
        printf("Parent (PID: %d) sleeping without wait...\n", getpid());
        sleep(30);  // Parent sleeps — child becomes zombie
        printf("Parent awake, now calling wait()\n");
        wait(NULL);
        printf("Child reaped, zombie gone.\n");
    }
    return 0;
}
During the 30-second sleep, run ps -l in another terminal. You'll see the child process with status Z (zombie).

5. Common Pitfalls

Pitfall 1: Assuming fork() creates a shared address space

Mistake: Students think child and parent share variables.
c
int x = 10;
fork();
x = 20;  // Each process has its own x!
Why: After fork(), each process has its own copy of memory (copy-on-write). Correct: Use IPC (shared memory, pipes) for communication.

Pitfall 2: Forgetting to handle all three fork() return values

Mistake: Only checking for 0 (child) and assuming success. Correct: Always check for -1 (fork failure)!
c
if (pid == -1) { perror("fork"); exit(1); }
if (pid == 0) { /* child */ } else { /* parent */ }

Pitfall 3: Creating zombies by never calling wait()

Mistake: Parent exits without waiting, leaving zombies. Solution: Always call wait() or waitpid(), or register SIGCHLD handler.

6. 📐 Key Formulas / Concepts

ConceptDefinitionKey Insight
ProcessProgram in executionActive entity with PCB
Context switchSaving/loading process statePure overhead (no useful work)
fork()Creates child processReturns 0 (child) or PID (parent)
exec()Replaces process imageNever returns on success
wait()Parent blocks for childPrevents zombies
ZombieProcess that exited but PCB retainedPCB memory leak
OrphanProcess whose parent exitedAdopted by init (PID 1)

7. 📝 Practice Questions

Q1: What is the output of this code? (Assume fork succeeds)
c
int main() {
    fork();
    printf("Hello\n");
    fork();
    printf("World\n");
    return 0;
}
Answer: The string "Hello" prints 2 times, and "World" prints 4 times.
Trace:
  • P0 starts → fork() → P0(Hello) + P1(Hello)
  • P0 fork() → P0(World) + P2(World)
  • P1 fork() → P1(World) + P3(World)
Total: 2 "Hello", 4 "World" Q2: Name three differences between a program and a process.
AspectProgramProcess
NaturePassive (disk)Active (memory + CPU)
LifetimePermanentTemporary
ResourcesNoneCPU, memory, files
Q3: How does the OS save and restore the context of a process during a context switch?
Answer: The OS saves the current register values (PC, SP, general-purpose registers) into the PCB of the current process. It then loads the saved registers from the PCB of the next process into the CPU. This involves:
  1. Trap to kernel mode (interrupt or system call)
  2. Save current process state to PCB
  3. Run scheduler to pick next process
  4. Load next process state from PCB
  5. Return to user mode at the saved PC Q4: What happens if a parent process terminates before its child?
Answer: The child becomes an orphan process. It gets adopted by the init process (PID 1), which periodically calls wait() to reap it. The orphan continues running normally but its parent PID becomes 1. Q5: Consider a system with context switch time of 20 μs and a time quantum of 10 ms. What percentage of CPU time is spent on context switching?
Answer:
  • Each context switch: 20 μs = 0.02 ms
  • Per time quantum: 2 context switches (one out, one in) = 0.04 ms
  • Overhead per quantum: 0.04 / (10 + 0.04) ≈ 0.4%
  • CPU utilization ≈ 99.6% Q6: Explain the difference between a zombie process and an orphan process.
Answer:
  • Zombie: Child has exited but parent hasn't called wait() yet. PCB is still allocated.
  • Orphan: Parent has exited but child is still running. Child is adopted by init (PID 1), which calls wait() automatically, so no zombie persists. Q7: What is the Process Control Block (PCB)? List at least 5 fields.
Answer: The PCB is a kernel data structure storing all information about a process. Fields: PID, Process State, Program Counter, CPU Registers, Memory Limits, Open Files, CPU Scheduling Info, Accounting Info, I/O Status. Q8: Draw the 5-state process model and list all valid transitions.
Answer: States: New → Ready → Running → Terminated, plus Ready → Running (dispatch), Running → Ready (preemption), Running → Waiting (I/O), Waiting → Ready (I/O complete). Q9: Write code using fork() where the child prints "Child" and the parent prints "Parent". Ensure the parent waits for the child.
c
#include <stdio.h>
#include <unistd.h>
#include <sys/wait.h>

int main() {
    pid_t pid = fork();
    if (pid == 0) {
        printf("Child\n");
    } else if (pid > 0) {
        wait(NULL);
        printf("Parent\n");
    }
    return 0;
}
Q10: What is the difference between exit() and _exit()?
Answer: exit() performs cleanup (flush buffers, call atexit handlers, close streams) then calls _exit(). _exit() immediately terminates the process. In child processes, _exit() is preferred to avoid flushing parent buffers.

8. 🔗 Cross-References

  • Week 2 - Threads: Compare processes vs threads (lighter weight)
  • Week 3 - CPU Scheduling: How the scheduler selects the next process
  • Week 5 - Synchronization: IPC between processes
  • BSCS3031 (CSD): Interrupt handling, system timer
  • BSCS3005 (C Programming): System calls in C Join Discord NextOS Structures & Boot
Document outline

Keep your place and jump directly to a heading.

Table of Contents
System Normal // Awaiting Context

Intelligence Hub

Navigate the knowledge graph to generate context. The Hub adapts dynamically to surface backlinks, related notes, and metadata insights.