Process States and Transitions
A process state represents the current condition of a process in the operating system. During its lifetime, a process transitions through several well-defined states. Understanding these states is crucial for grasping how the OS manages processes.
The 5 Process States

Process transitions through 5 states: New → Ready → Running ↔ Waiting → Terminated
State 1: NEW
Process is being created by os in Disk (PCB allocated, not in RAM yet).
When: Right after fork() (Unix) or CreateProcess() (Windows) system call.
What happens:
- OS allocates a PCB
- Process code is loaded from disk
- Memory is allocated but process is NOT in RAM yet
- Process hasn’t started executing
Example:
pid_t pid = fork(); // ← Process P1 is in NEW state here
Next State: Ready (when loaded into RAM)
State 2: READY
Loaded in RAM, waiting in the “Ready Queue” for the CPU.
When: After loaded into memory, but scheduler hasn’t allocated CPU yet
What happens:
- Process is loaded in RAM
- All resources are allocated
- Process is waiting in the “Ready Queue”
- Many processes can be in READY state simultaneously
- Scheduler will pick one based on priority
Example:
Ready Queue: [P1] [P2] [P3] [P4]
↑
Next to run?
Next State: Running (when scheduler allocates CPU)
State 3: RUNNING
Currently executing instructions on the CPU.
When: Scheduler has allocated CPU time to this process
What happens:
- Process instructions are executing
- CPU registers contain process’s data
- Program Counter points to current instruction
- Only ONE process can be in RUNNING state at a time (on single-core CPU)
Example:
printf("I'm running!\n"); // ← This line is executing NOW
// This process is in RUNNING state
Duration: Limited by time quantum (typically 10-100 milliseconds)
Next State(s):
- Ready: Time quantum expires (context switch)
- Waiting: Process calls I/O or blocking operation
- Terminated: Process calls
exit()
State 4: WAITING (Blocked)
Paused, waiting for an event (I/O, Mutex).
When: Process needs something it doesn’t have (I/O, lock, etc.)
What happens:
- Process can’t continue without the event
- CPU is released for other processes to use
- Process is moved to “Wait Queue” for that specific resource
- Process will remain blocked until event occurs
Common reasons for WAITING:
// Scenario 1: Waiting for file I/O
read(fd, buffer, 100); // ← Blocks until data is read from disk
// Scenario 2: Waiting for user input
scanf("%d", &x); // ← Blocks until user types
// Scenario 3: Waiting for a lock
pthread_mutex_lock(&lock); // ← Blocks until lock is available
// Scenario 4: Waiting for network I/O
recv(socket, buffer, 100); // ← Blocks until data arrives
// Scenario 5: Sleeping for a duration
sleep(5); // ← Blocks for 5 seconds
// Scenario 6: Waiting for child process
wait(&status); // ← Blocks until child exits
Example flow:
Process executes:
read(disk_fd, buffer, 1024);
↓
Disk is slow, process can not continue
↓
Process moves to WAITING state
CPU scheduler picks another READY process
Disk reads data...
↓
Data is ready, interrupt occurs
Process moves from WAITING → READY
Waits for CPU again...
Next State: Ready
State 5: TERMINATED
Process execution has finished
When: Process calls exit() or is killed
What happens:
- Process stops executing
- OS performs cleanup:
- Closes file descriptors
- Deallocates memory
- Terminates child processes (if any)
- Notifies parent process of exit status
- PCB may remain briefly (for parent to read exit status)
- Eventually removed from process table
Normal Termination:
int main() {
printf("Doing work...\n");
return 0; // ← Process terminates normally
}
Abnormal Termination:
kill -9 <PID> # ← OS forcefully terminates process
Next State: (removed from system)
State Transitions in Detail
1. NEW → READY
Trigger: OS loads process into RAM
When fork() completes:
├─ PCB created
├─ Memory allocated
├─ Process image loaded
└─ Process moves to READY
2. READY → RUNNING
Trigger: Scheduler allocates CPU time
// Multiple processes waiting:
Ready Queue: [P1] [P2] [P3] [P4]
Scheduler decision:
if (P1.priority > P2.priority) {
P1 → RUNNING
}
// Now P1 executes while others wait
3. RUNNING → READY
Trigger: Time quantum expires or higher priority process arrives
Time Quantum Expired:
RUNNING P1 (10ms used)
↓
Scheduler timer interrupt
↓
Save P1 state to PCB
↓
P1 → READY (back to queue)
↓
Load P2 from READY
↓
P2 → RUNNING
4. RUNNING → WAITING
Trigger: Process executes blocking operation
// Process is executing...
RUNNING:
read(fd, buffer, 100); // ← Can't continue without data!
↓
OS detects blocking operation
↓
Save state to PCB
↓
Move process to WAITING
↓
Scheduler picks another READY process
↓
Data arrives (interrupt)
↓
Process → READY (waits for CPU again)
5. WAITING → READY
Trigger: The waited-for event occurs
Waiting for disk read:
read() call waiting...
↓ [Disk controller finishes reading]
Disk I/O interrupt occurs
↓
OS wakes up process
↓
Process → READY queue
Now it waits for CPU again (not for disk anymore)
6. RUNNING → TERMINATED
Trigger: Process calls exit() or receives SIGKILL
// Normal termination
RUNNING:
printf("Done!\n");
return 0; // ← exit(0) called
↓
OS cleanup:
├─ Close files
├─ Free memory
├─ Notify parent
└─ Remove from table
Example: Web Server
Multiple client connections:
Client 1 Client 2 Client 3
│ │ │
├──→ P1 ├──→ P2 ├──→ P3
│ │ │
Timeline:
T=0ms: P1 RUNNING (processing request)
P2 READY (waiting for CPU)
P3 READY (waiting for CPU)
T=5ms: P1 hits I/O (reads from disk)
P1 → WAITING
P2 → RUNNING (scheduler picks next)
T=10ms: P2 finishes quickly, calls exit()
P2 → TERMINATED
P3 → RUNNING
T=15ms: P1 disk read completes
P1 → READY
P3 still RUNNING
T=20ms: P3 time quantum expires
P3 → READY
P1 → RUNNING (back with data)