Processes execute in arrival order — pure FIFO queue.
No preemption: once running, a process keeps the CPU until it blocks or exits.
Convoy effect: a single long job holds the CPU while short jobs wait idle, inflating average waiting time.
Worst-case average waiting time grows linearly with burst time variance — not robust for interactive loads.
Production trap: using FCFS for mixed workloads (CPU + I/O) causes I/O devices to starve, tanking throughput.
✦ Definition~90s read
What is FCFS Scheduling?
First-Come, First-Served (FCFS) is the simplest CPU scheduling algorithm, where processes are executed in the exact order they arrive in the ready queue. It's a non-preemptive, queue-based discipline — once a process gets the CPU, it runs to completion (or until it blocks for I/O).
★
FCFS is the simplest scheduling algorithm — processes run in the order they arrive, like a queue at a ticket counter.
FCFS is the scheduling equivalent of a single-file line at a deli counter: fair in principle, but disastrous when a long-running process holds up everyone behind it. In operating systems, it's often the default scheduler for batch systems or the fallback when no other policy is specified.
Real-world examples include early mainframe job scheduling and some simple embedded systems where predictability trumps performance.
FCFS's fatal flaw is the convoy effect, which this article explores through the lens of a payment API under burst load. When a CPU-bound process (e.g., a cryptographic signature verification) grabs the queue head, all subsequent I/O-bound processes (e.g., database queries for transaction lookups) pile up behind it.
The CPU sits idle while the I/O-bound processes wait, then the I/O devices starve when the CPU-bound process finishes and the burst of I/O processes flood the system. This creates a cascading underutilization of both CPU and I/O — exactly what kills latency-sensitive APIs.
Metrics like average turnaround time and waiting time balloon: under FCFS, a 100ms CPU burst followed by 1000 1ms I/O requests can yield average waiting times of ~50ms, versus <1ms with Round Robin.
In practice, FCFS is only appropriate for systems where process burst times are uniformly short and predictable — think dedicated hardware controllers or single-user systems with no concurrency. For any real-time or interactive workload (web servers, payment gateways, database engines), FCFS is a non-starter.
Compared to SJF (Shortest Job First), which minimizes average waiting time but risks starvation, or Round Robin, which provides fairness via time quanta, FCFS offers zero control over response time variance. The convoy effect isn't a theoretical edge case — it's the reason modern schedulers (Linux CFS, Windows NT scheduler) use preemptive, priority-based algorithms.
If you're building a payment API and see tail latency spikes under load, FCFS is likely the culprit hiding in your thread pool or database connection scheduler.
Plain-English First
FCFS is the simplest scheduling algorithm — processes run in the order they arrive, like a queue at a ticket counter. Whoever arrives first gets served first. Simple and fair in principle, but a long process can make everything behind it wait — the convoy effect.
FCFS is the algorithm you implement when you have a queue and zero information about job durations. It is fair in the sense that arrival order is respected — no process waits longer than all processes that arrived before it. But 'fair' does not mean 'efficient', and the convoy effect makes FCFS genuinely harmful for interactive workloads.
Understanding FCFS matters not for implementing it (it is trivially a FIFO queue) but for understanding what it optimises and what it sacrifices. Every scheduling algorithm trades off fairness, average waiting time, response time, and throughput differently. FCFS optimises arrival-order fairness at the cost of average waiting time. This trade-off analysis is the interview skill being tested.
Why FCFS Scheduling Fails Under Burst Load
First-Come, First-Served (FCFS) is the simplest scheduling algorithm: tasks execute in the exact order they arrive, using a FIFO queue. The core mechanic is non-preemptive — once a task gets the CPU, it runs to completion. This means no context-switch overhead, but it also means a single long task can block every subsequent task, regardless of priority or urgency.
In practice, FCFS exhibits the convoy effect: a long CPU-bound process holds the queue, forcing all I/O-bound tasks to wait. For a payment API, a single large report generation request (say, 2 seconds of CPU) can delay 1000 payment transactions behind it, each adding milliseconds of latency. The average waiting time balloons as the variance in burst times increases — mathematically, the average turnaround time is O(n) in the worst case.
Use FCFS only when all tasks have similar, predictable execution times — for example, a batch processing pipeline where each job is identical. In real-time or interactive systems, FCFS is a liability. Understanding its convoy effect is critical because it's the default behavior of many naive queue implementations (e.g., a simple BlockingQueue in Java) that teams assume are safe.
⚠ Convoy Effect Blind Spot
FCFS is not 'fair' — it penalizes short tasks that arrive after a long one, causing tail latency spikes that violate SLAs.
📊 Production Insight
Payment API with a mixed workload: a single /report endpoint (CPU-heavy) blocks all /charge requests.
Symptom: P99 latency jumps from 50ms to 2s during report generation, triggering timeout alerts.
Rule: Never use FCFS for mixed workloads — always separate fast and slow paths or use priority scheduling.
🎯 Key Takeaway
FCFS is non-preemptive — a long task blocks all later tasks until completion.
Convoy effect turns bursty workloads into latency disasters for short tasks.
Only use FCFS when task durations are uniform and predictable.
thecodeforge.io
Fcfs Scheduling Algorithm
Algorithm and Metrics
Key metrics
Completion Time (CT): When the process finishes
Turnaround Time (TAT): CT
Arrival Time
Waiting Time (WT): TAT
Burst Time
Response Time: Time from arrival to first execution (= WT for non-preemptive)
FCFS is trivially a FIFO queue. You sort processes by arrival time, then execute each to completion. The metrics tell the real story: average waiting time can skyrocket when a long job arrives early.
fcfs.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
deffcfs(processes: list[dict]) -> list[dict]:
"""
processes: list of {pid, arrival, burst}
Returns processes with ct, tat, wt added.
"""
# Sort by arrival time
procs = sorted(processes, key=lambda p: p['arrival'])
current_time = 0
results = []
for p in procs:
start = max(current_time, p['arrival'])
ct = start + p['burst']
tat = ct - p['arrival']
wt = tat - p['burst']
current_time = ct
results.append({**p, 'start': start, 'ct': ct, 'tat': tat, 'wt': wt})
return results
processes = [
{'pid':'P1','arrival':0,'burst':24},
{'pid':'P2','arrival':1,'burst':3},
{'pid':'P3','arrival':2,'burst':3},
]
results = fcfs(processes)
print(f"{'PID':<4} {'AT':>3} {'BT':>3} {'ST':>3} {'CT':>3} {'TAT':>4} {'WT':>4}")
for r in results:
print(f"{r['pid']:<4} {r['arrival']:>3} {r['burst']:>3} {r['start']:>3} {r['ct']:>3} {r['tat']:>4} {r['wt']:>4}")
avg_tat = sum(r['tat'] for r in results) / len(results)
avg_wt = sum(r['wt'] for r in results) / len(results)
print(f"\nAverage TAT: {avg_tat:.2f}")
print(f"Average WT: {avg_wt:.2f}")
Output
PID AT BT ST CT TAT WT
P1 0 24 0 24 24 0
P2 1 3 24 27 26 23
P3 2 3 27 30 28 25
Average TAT: 26.00
Average WT: 16.00
📊 Production Insight
These numbers hide a trap: the average WT of 16ms comes entirely from the two short jobs. P1 never waits. In a real system, if those short jobs are interactive, users feel a 25ms delay — unacceptable.
If you're building a metric dashboard, always track the distribution of waiting times, not just the average. The 99th percentile reveals the convoy victims.
🎯 Key Takeaway
FCFS arrival order is fair but waiting time depends entirely on the burst of earlier processes.
Average waiting time can be misleading — monitor percentiles.
If you see one long process inflating the mean, you're looking at a convoy.
The Convoy Effect
In the example above, P2 and P3 each take only 3ms but wait 23ms and 25ms because P1 (24ms) arrived first. This is the convoy effect — short processes form a convoy behind a long one.
If we ran P2, P3, P1 instead (SJF order)
P2: WT=0, P3: WT=2, P1: WT=5
Average WT = 2.33ms vs 16ms for FCFS
This is why FCFS has poor average waiting time for mixed workloads.
⚠ Convoy Effect
FCFS is particularly bad when a CPU-bound process arrives before many I/O-bound processes. The CPU-bound process holds the CPU while I/O-bound processes (which could be doing I/O) wait idle.
📊 Production Insight
Convoy effect is not just a textbook problem. In any production system mixing compute-heavy and light tasks, FCFS can cause I/O devices to starve. The I/O-bound processes could issue disk reads, but they sit blocked on CPU while the disk sits idle. Throughput drops because the system isn't overlapping CPU and I/O operations.
Debugging tip: If CPU utilization is low but I/O-bound processes have high waiting times, check the scheduler policy.
🎯 Key Takeaway
Convoy effect wastes I/O bandwidth, not just CPU time.
The fix is preemption — don't let one process monopolize the CPU.
If you cannot preempt, at least isolate batch jobs to separate queues.
thecodeforge.io
Fcfs Scheduling Algorithm
Gantt Chart Representation
A Gantt chart visually shows which process runs at each time interval. For FCFS, the chart is simply the processes in arrival order, each spanning its burst duration. This representation makes the convoy effect obvious: long bars push short bars to the right.
gantt.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
defprint_gantt(results: list[dict]) -> None:
print('Gantt Chart:')
bar = '|'
times = '0'for r in results:
bar += f" {r['pid']:^5}|"
times += f"{r['ct']:>7}"print(bar)
print(times)
print_gantt(results)
Output
Gantt Chart:
| P1 | P2 | P3 |
0 24 27 30
📊 Production Insight
In a real system, you can generate a Gantt-like timeline from /proc/[pid]/schedstat. Plotting cumulative CPU time per process reveals if a single long task dominates early time slices.
If you see a flat line for short tasks while a long task runs, that's visual proof of convoy.
🎯 Key Takeaway
Gantt charts expose scheduling unfairness at a glance.
Automate their generation from performance monitoring data.
Long contiguous bars = convoy; many small bars = preemptive fairness.
When to Use FCFS in Practice
FCFS is appropriate only when
All jobs have roughly equal burst times (e.g., batch file processing with similar file sizes).
Order must be strictly preserved (e.g., transactions that must commit in arrival sequence).
No prior information about job durations exists and you cannot risk priority inversion.
FCFS is not appropriate for
Interactive systems where response time matters.
Mixed workloads with heterogeneous burst times.
Real-time systems where deadlines must be met.
In most general-purpose operating systems, FCFS is used only as a fallback scheduler for equal-priority processes under SCHED_OTHER. Linux's Completely Fair Scheduler (CFS) is fundamentally different — it's a weighted fair queuing scheduler that preempts to maintain fairness.
Mental Model
FCFS in the OS Ecosystem
FCFS is the 'null model' of scheduling — it's what happens when you don't make any decisions.
No decision: just a queue. Predictable in behaviour, unpredictable in performance.
Linux CFS targets a 1ms scheduling granularity — the opposite of FCFS's no-granularity.
FCFS survives as a special case for cooperative multitasking or dispatcher systems where preemption is impossible.
📊 Production Insight
You'll rarely configure a modern OS scheduler to pure FCFS because the kernel already does preemptive time-sharing. But FCFS emerges accidentally when a thread pool uses a single worker thread and a FIFO work queue. That's where the real convoy problems live.
Rule: Any single-threaded FIFO queue in a concurrent system is a potential FCFS convoy trap.
🎯 Key Takeaway
FCFS is the default when you opt out of scheduling decisions.
Watch out for accidental FCFS in thread pools and dispatchers.
Real-time and interactive systems must preempt.
FCFS vs. SJF vs. Round Robin
Comparing scheduling algorithms around burst time variance:
Algorithm
Average Waiting Time
Starvation Risk
Preemptive
FCFS
High with variance
None (everyone runs eventually)
No
SJF (non-preemptive)
Optimal for given arrival order
Yes, long processes
No
Round Robin (preemptive)
Moderate, depends on quantum
Low
Yes
FCFS minimises the maximum waiting time for processes with the same arrival order — that's its fairness guarantee. But it maximises average waiting time when burst times vary.
SJF exploits knowledge of burst times to minimise average waiting time, but can starve long processes. Round Robin trades off average waiting time for response time — good for interactive workloads.
In production, you rarely pick one in isolation. Hybrid schedulers like CFS combine elements: target latency (like RR) with fairness (like FCFS) and dynamic priority adjustments.
📊 Production Insight
In real systems, burst times are rarely known. SJF is often estimated from historical data (e.g., exponential averaging), which introduces its own complexity. FCFS avoids this estimation entirely but pays the convoy cost.
If you're building a job scheduler from scratch, start with FCFS for simplicity, then add preemption when you measure convoy effect in production.
🎯 Key Takeaway
No single algorithm dominates — trade-offs are inevitable.
FCFS is the baseline; anything more sophisticated must justify its complexity.
Measure your workload's burst time distribution before choosing.
Choosing a Scheduling Policy
IfAll jobs are CPU-bound and similar length
→
UseFCFS is fine — simplest, no overhead.
IfInteractive response time is critical
→
UseUse Round Robin or CFS — preemption ensures fairness in response time.
IfYou know job burst times beforehand
→
UseSJF minimises average waiting time, but watch for starvation — implement aging.
How FCFS Actually Works (No Mysticism)
FCFS is the dumbest scheduling algorithm you'll ever use. That's its superpower. When a process arrives, it gets thrown at the tail of a FIFO queue. The CPU pulls from the head, runs the process to completion (or until it blocks on I/O), then moves to the next. No preemption, no priority, no fancy logic.
The kernel maintains a simple linked list of task_struct entries. Insertion is O(1). Dequeue is O(1). The scheduler has zero decisions to make. That's it. No quantum timers, no context-switch overhead from preemption, no starvation logic because every process eventually hits the front of the line.
Where this breaks down is when you have a long CPU-bound process holding the head of the queue. Every interactive process behind it waits. And waits. The FIFO queue becomes a bottleneck that makes your system feel like it's running on a 486. Windows 95 used a variant of FCFS for some legacy drivers. Users threw their mice at the screen. There's your history lesson.
FCFSScheduler.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// io.thecodeforge — dsa tutorialimport java.util.LinkedList;
import java.util.Queue;
classProcess {
String id;
int burstTime;
Process(String id, int burstTime) {
this.id = id;
this.burstTime = burstTime;
}
}
publicclassFCFSScheduler {
publicstaticvoidmain(String[] args) {
Queue<Process> readyQueue = newLinkedList<>();
readyQueue.add(newProcess("P1", 5));
readyQueue.add(newProcess("P2", 3));
readyQueue.add(newProcess("P3", 8));
int time = 0;
while (!readyQueue.isEmpty()) {
Process current = readyQueue.poll();
System.out.println("Time " + time + ": " + current.id + " starts");
time += current.burstTime;
System.out.println("Time " + time + ": " + current.id + " finishes");
}
}
}
Output
Time 0: P1 starts
Time 5: P1 finishes
Time 5: P2 starts
Time 8: P2 finishes
Time 8: P3 starts
Time 16: P3 finishes
⚠ Production Trap:
FCFS in a real OS kills interactive response. A 10-second backup job will stall your UI thread. Always pair FCFS with a preemptive fallback for time-sensitive processes.
🎯 Key Takeaway
FCFS is a FIFO queue. No decisions, no overhead, no fairness for short tasks.
Example with Different Arrival Times (The Real World)
In production, processes don't all show up at time zero. That's a classroom fantasy. Real workloads have staggered arrivals, I/O bursts, and users who close browsers mid-stream. Let's build a scenario that actually hurts.
Three processes: P1 arrives at 0 with a 7ms CPU burst. P2 arrives at 2ms with a 4ms burst. P3 arrives at 4ms with a 1ms burst. FCFS doesn't care about burst length. P1 runs from 0 to 7. P2 waits until 7, runs to 11. P3 waits until 11, runs to 12. P3's tiny 1ms job sits idle for 7ms while P1 churns.
Calculate turnaround time (completion minus arrival): P1 = 7, P2 = 9, P3 = 8. Average = 8ms. Waiting time (turnaround minus burst): P1 = 0, P2 = 5, P3 = 7. Average = 4ms. P3 waited 7x its execution time. That's the Convoy Effect in its purest form.
Now imagine that P3 is a mouse movement handler. You've just introduced a 7ms input lag. Users don't tolerate that. This is why FCFS is relegated to batch systems and background jobs where latency doesn't matter.
When calculating wait times by hand, always subtract arrival from start time, not start from finish. Keeps you from confusing turnaround with waiting.
🎯 Key Takeaway
Staggered arrivals expose FCFS's weakness: short tasks get punished by the Convoy Effect.
Problem 1: Starvation of Late Arrivals Isn't Fairness
You'd think first-come-first-served is fair by definition. It's not. Late arrivals in FCFS don't just wait — they can wait indefinitely under sustained load. If a CPU-bound process arrives first and runs for 10 seconds, every interactive process that shows up second gets buried behind it. That's not fairness; that's a single-threaded bottleneck masquerading as a policy.
The real problem is that FCFS has no preemption. Once a process gets the CPU, it holds it until it voluntarily yields — usually by completing an I/O wait or terminating. Under burst load, this means short tasks get stuck behind long ones. The average waiting time balloons, and worst-case response time becomes unpredictable.
Why this matters in production: You can't build a real-time system on FCFS. A single misbehaving or oversized job tanks latency for everyone else. If you're running a web server, that's the difference between a 200ms response and a 5-second timeout.
StarvationDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// io.thecodeforge — dsa tutorialclassProcess {
String name; int burst;
Process(String n, int b) { name = n; burst = b; }
}
publicclassStarvationDemo {
publicstaticvoidmain(String[] args) {
Process[] procs = {
newProcess("BigCalc", 10000),
newProcess("WebReq", 2),
newProcess("APICall", 5)
};
int time = 0;
for (Process p : procs) {
System.out.println(p.name + " starts at " + time);
time += p.burst;
System.out.println(p.name + " finishes at " + time);
}
System.out.println("Short tasks waited " + (procs[2].burst + procs[1].burst) + " ms");
}
}
Output
BigCalc starts at 0
BigCalc finishes at 10000
WebReq starts at 10000
WebReq finishes at 10002
APICall starts at 10002
APICall finishes at 10007
Short tasks waited 10007 ms
⚠ Production Trap:
Don't confuse FIFO ordering with fairness. FCFS guarantees order, not bounded wait time. In real systems, couple FCFS with timeout mechanisms or move to preemptive scheduling.
🎯 Key Takeaway
FCFS guarantees order, not fairness — short jobs can starve behind long ones with no preemption.
Solution: Preemptive FCFS? No, Use the Right Tool
You can't fix FCFS by making it preemptive — that's not FCFS anymore, that's Round Robin with a quantum. The real solution is admitting FCFS has a narrow sweet spot. If you need bounded response times, use a preemptive scheduler. If you need throughput for batch workloads, FCFS is fine — just don't mix long and short jobs on the same queue.
When you're stuck with FCFS in a legacy system, mitigate by isolating workloads. Use multiple queues: one for short interactive tasks (handled by SJF) and one for long batch jobs (handled by FCFS). This pattern shows up in Linux's Completely Fair Scheduler — it's not preemption that saves you, it's classification.
The production-level fix: never let a single queue mix CPU-bound and I/O-bound processes. Or, if you must, cap the burst time per process and preempt after a threshold. But then you're not running FCFS anymore. Be honest about what you need and choose the algorithm that delivers it.
MitigationDemo.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
// io.thecodeforge — dsa tutorialimport java.util.*;
publicclassMitigationDemo {
staticclassJob {
String name; int burst; boolean isShort;
Job(String n, int b, boolean s) { name = n; burst = b; isShort = s; }
}
publicstaticvoidmain(String[] args) {
Queue<Job> shortQ = newLinkedList<>();
Queue<Job> longQ = newLinkedList<>();
shortQ.add(newJob("Web", 2, true));
shortQ.add(newJob("API", 5, true));
longQ.add(newJob("Batch", 10000, false));
int time = 0;
while (!shortQ.isEmpty() || !longQ.isEmpty()) {
Job j = shortQ.poll();
if (j == null) j = longQ.poll();
if (j != null) {
System.out.println(j.name + " starts at " + time);
time += j.burst;
System.out.println(j.name + " finishes at " + time);
}
}
System.out.println("Short jobs not blocked by batch");
}
}
Output
Web starts at 0
Web finishes at 2
API starts at 2
API finishes at 7
Batch starts at 7
Batch finishes at 10007
Short jobs not blocked by batch
💡Senior Shortcut:
Separate queues for short and long jobs. Run short ones SJF, long ones FCFS. That's the bare minimum for sane latency — no kernel wizardry required.
🎯 Key Takeaway
Don't force FCFS to be fair — isolate job types into separate queues and use the right scheduler for each.
First-Come, First-Served Scheduling
First-come, first-served (FCFS) scheduling is the simplest CPU scheduling algorithm, where processes are executed in the order they arrive in the ready queue. It follows a non-preemptive, FIFO (First In, First Out) discipline: the first process to request the CPU gets it, and holds it until completion or I/O block. This mimics a real-world queue like a grocery checkout. FCFS is fundamental in operating systems and discrete event simulation because it models natural fairness—no process jumps ahead. However, its simplicity hides severe performance issues under bursty workloads, as average waiting time can balloon when a long CPU burst blocks shorter ones. The algorithm's behavior is purely deterministic: given arrival times and burst durations, the order and completion times are fixed. FCFS is the baseline against which all other scheduling algorithms are measured, despite rarely being used alone in modern systems.
FCFSBasic.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// io.thecodeforge — dsa tutorial// 25 lines maxpublicclassFCFSBasic {
publicstaticvoidmain(String[] args) {
int[] burst = {10, 5, 8}; // msint[] arrival = {0, 1, 2};
int n = burst.length;
int[] completion = newint[n];
int[] waiting = newint[n];
int time = 0;
System.out.println("FCFS Scheduling:");
for (int i = 0; i < n; i++) {
if (time < arrival[i]) time = arrival[i];
completion[i] = time + burst[i];
waiting[i] = time - arrival[i];
System.out.println("P" + i + ": arrival=" + arrival[i] + ", burst=" + burst[i] + ", completion=" + completion[i] + ", waiting=" + waiting[i]);
time = completion[i];
}
}
}
Output
FCFS Scheduling:
P0: arrival=0, burst=10, completion=10, waiting=0
P1: arrival=1, burst=5, completion=15, waiting=9
P2: arrival=2, burst=8, completion=23, waiting=13
⚠ Production Trap:
Never assume FCFS is fair because it processes in order. Late-arriving short processes can starve behind a long-running CPU hog—this is not fairness, it's accidental punishment.
🎯 Key Takeaway
FCFS executes processes strictly in arrival order—simple but dangerous for bursty workloads.
thecodeforge.io
Fcfs Scheduling Algorithm
Explanation, Advantages, Disadvantages, and Characteristics
Explanation: FCFS is non-preemptive; once a process gets the CPU, it runs until it terminates or blocks. The scheduler maintains a simple FIFO queue. When a new process arrives, it's appended to the rear. The CPU picks the head of the queue. Advantages: (1) Extremely easy to implement—just a queue. (2) No starvation for CPU-bound processes if they all arrive early; every process eventually runs. (3) Low context-switching overhead. Disadvantages: (1) High average waiting time under bursty loads (convoy effect). (2) Poor response time for interactive processes. (3) Not suitable for time-sharing systems. Characteristics: Non-preemptive, starvation-free in a strict sense (every arrival gets CPU eventually), but average turnaround time can be large. It's deterministic and predictable. The algorithm favors long CPU bursts over short ones, which is the opposite of optimal for minimizing mean wait time. FCFS is the baseline, but in practice, it's used only where order matters (e.g., batch processing) or as a fallback.
FCFSMetrics.javaJAVA
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// io.thecodeforge — dsa tutorial// 25 lines maxpublicclassFCFSMetrics {
publicstaticvoidmain(String[] args) {
int[] burst = {6, 2, 8}; // ms
int[] arrival = {0, 0, 0}; // same timeint n = burst.length;
int totalWait = 0, totalTurn = 0;
int time = 0;
System.out.println("FCFS Metrics (all arrive at 0):");
for (int i = 0; i < n; i++) {
int completion = time + burst[i];
int turn = completion - arrival[i];
int wait = time - arrival[i];
totalWait += wait;
totalTurn += turn;
System.out.println("P" + i + ": burst=" + burst[i] + ", wait=" + wait + ", turn=" + turn);
time = completion;
}
System.out.println("Avg wait: " + (totalWait/(double)n) + " ms, Avg turn: " + (totalTurn/(double)n) + " ms");
}
}
Output
FCFS Metrics (all arrive at 0):
P0: burst=6, wait=0, turn=6
P1: burst=2, wait=6, turn=8
P2: burst=8, wait=8, turn=16
Avg wait: 4.67 ms, Avg turn: 10.0 ms
🔥Production Trap:
FCFS is rarely used alone in modern OS kernels. Its simplicity is a trap—deploy it only when process order must match arrival order (e.g., print spooling).
🎯 Key Takeaway
FCFS is simple and starvation-free but yields high average wait times—characterized by non-preemption and FIFO ordering.
● Production incidentPOST-MORTEMseverity: high
Convoy Effect Brings Down an E-Commerce Checkout Service
Symptom
Response time for payment API calls rose from <200ms to >15 seconds during the first minute of every hour. The database showed no contention and queries were fast.
Assumption
The team assumed the database was the bottleneck because queries appeared slow under load. They added read replicas and increased connection pool sizes — no improvement.
Root cause
A nightly batch job (CPU-bound, burst 15s) arrived at the same thread pool used for payment requests. FCFS scheduling queued all incoming payment processes behind the batch job, causing convoy effect. The thread pool had only one worker thread.
Fix
Separated batch processing to a dedicated thread pool or worker with lower priority. Applied priority scheduling (batch as low, interactive as high) or switched to a preemptive scheduler like Round Robin with a short time quantum.
Key lesson
Never mix CPU-bound batch jobs and interactive I/O-bound requests on the same FCFS queue.
Measure queue depth under load — it reveals convoy effect faster than response times alone.
FCFS belongs in batch systems with homogeneous job sizes, not mixed workloads.
Production debug guideHow to identify convoy effect and confirm FCFS behaviour in production4 entries
Symptom · 01
Wide gap in completion times between short and long jobs despite low CPU utilization
→
Fix
Check process arrival times and durations. Plot waiting time vs burst time — a strong positive correlation indicates convoy effect under FCFS.
Symptom · 02
I/O-bound processes have high waiting time but the disk is idle
→
Fix
Verify the scheduler policy (ps -eo pid,comm,policy on Linux). If policy is SCHED_OTHER and no priorities are set, the default is essentially FCFS for equal priority tasks.
Symptom · 03
Response time spikes correlate with the start of a single long-running process
→
Fix
Trace process start times with /proc/[pid]/stat start time. Compare against spike timestamps. If the long process started seconds before the spike, FCFS convoy is likely.
Symptom · 04
Thread pool metrics show an ever-increasing queue depth after a specific job submission
→
Fix
Inspect thread pool implementation. If it uses a FIFO work queue, any long task will block subsequent short tasks. Switch to a work-stealing or priority queue.
★ Quick FCFS Debug CommandsCommands to detect convoy effect and measure scheduling delays in real time
High average waiting time, short tasks delayed−
Immediate action
List processes sorted by arrival time and record cumulative waiting times
Commands
ps -eo pid,comm,etime,pri,nice --sort=start_time
for p in $(pgrep -f batch); do cat /proc/$p/sched | head -20; done
Fix now
Renice the long batch job to lower priority: renice +10 -p <pid>
Thread pool queue depth growing while CPU idle+
Immediate action
Check thread pool work queue size and oldest task age
Restart with a custom thread pool that uses a priority queue or separate pools for different job types
FCFS vs SJF vs Round Robin
Algorithm
Preemptive?
Avg. Wait Time
Starvation Risk
Best Use Case
FCFS
No
High with burst variance
None
Batch systems with homogeneous jobs
SJF (non-preemptive)
No
Optimal (theoretical)
High (long tasks)
When burst times known and short jobs dominate
Round Robin
Yes (time quantum)
Moderate, depends on quantum
Low
Interactive workloads, time-sharing
⚙ Quick Reference
8 commands from this guide
File
Command / Code
Purpose
fcfs.py
def fcfs(processes: list[dict]) -> list[dict]:
Algorithm and Metrics
gantt.py
def print_gantt(results: list[dict]) -> None:
Gantt Chart Representation
FCFSScheduler.java
class Process {
How FCFS Actually Works (No Mysticism)
FCFSStaggeredArrivals.java
class TimedProcess {
Example with Different Arrival Times (The Real World)
StarvationDemo.java
class Process {
Problem 1
MitigationDemo.java
public class MitigationDemo {
Solution
FCFSBasic.java
public class FCFSBasic {
First-Come, First-Served Scheduling
FCFSMetrics.java
public class FCFSMetrics {
Explanation, Advantages, Disadvantages, and Characteristics
Key takeaways
1
FCFS
sort by arrival, execute in order — non-preemptive.
2
Waiting Time = Turnaround Time - Burst Time. Turnaround Time = Completion - Arrival.
3
Convoy effect
short processes wait behind long ones → high average waiting time.
4
Simple to implement (FIFO queue) but rarely optimal.
5
Best used when all processes have similar burst times or process order must be preserved.
Common mistakes to avoid
3 patterns
×
Assuming FCFS is 'fair' for all metrics
Symptom
Short interactive processes experience high latency, users complain, but the scheduler report shows 'no process waited more than average'.
Fix
Track wait time percentiles (p99, p999) rather than just average. Educate the team that FCFS fairness is only arrival-order fairness, not performance fairness.
×
Using FCFS for I/O-heavy workloads because 'it's simple'
Symptom
CPU utilization is low (< 20%) but throughput is terrible. I/O devices are idle while processes sit in the run queue.
Fix
Switch to a preemptive scheduler (e.g., RR with quantum 10-50ms) to allow I/O-bound processes to issue requests and overlap I/O with CPU.
×
Implementing a thread pool with a single FIFO work queue and claiming it's 'FCFS scheduling'
Symptom
A long task in the queue blocks all subsequent short tasks. No parallelism despite multiple cores.
Fix
Use multiple worker threads, or a work-stealing queue (e.g., ForkJoinPool in Java), or a priority queue that prefers short tasks.
Explain the convoy effect in FCFS scheduling and show it with an example...
Q02JUNIOR
Is FCFS preemptive or non-preemptive? What are the implications?
Q03SENIOR
When would you choose FCFS over other scheduling algorithms in a product...
Q04SENIOR
Calculate average waiting time for FCFS with processes P1(AT=0,BT=8), P2...
Q05JUNIOR
Does FCFS cause starvation? Explain.
Q01 of 05SENIOR
Explain the convoy effect in FCFS scheduling and show it with an example.
ANSWER
The convoy effect occurs when a long CPU-bound process arrives before several short I/O-bound processes. The long process holds the CPU, forcing the short processes to wait. This increases average waiting time and wastes I/O bandwidth because the I/O devices remain idle while short processes could have issued requests.
Example: P1 (burst 24), P2 (burst 3), P3 (burst 3) arrive at times 0,1,2. Under FCFS, P1 runs first, P2 waits 23ms, P3 waits 25ms. Average WT = 16ms. Under SJF, P2 and P3 run first, average WT = 2.33ms. The convoy costs 13.67ms in average waiting time.
Q02 of 05JUNIOR
Is FCFS preemptive or non-preemptive? What are the implications?
ANSWER
FCFS is non-preemptive. Once a process starts executing, it holds the CPU until it voluntarily yields (e.g., I/O wait, termination) or blocks. This means no context switch overhead during a process's burst, but it also means a single long process can delay all others arbitrarily. Non-preemptive scheduling is simpler but not responsive to urgent or interactive tasks.
Q03 of 05SENIOR
When would you choose FCFS over other scheduling algorithms in a production system?
ANSWER
When:
- All processes have roughly equal burst times (so convoy effect is minimal).
- Order preservation is a hard requirement (e.g., transaction logs).
- You have no prior knowledge of job lengths and want to guarantee no starvation.
- Overhead must be close to zero (FCFS is just a queue).
In practice, modern OS schedulers like CFS do not use pure FCFS, but dedicated batch processing systems (e.g., job schedulers like AutoSys with single-executor queues) may effectively run FCFS.
Q04 of 05SENIOR
Calculate average waiting time for FCFS with processes P1(AT=0,BT=8), P2(AT=1,BT=4), P3(AT=2,BT=2).
ANSWER
Order by arrival: P1 then P2 then P3.
- P1: start=0, CT=8, WT=0.
- P2: start=8, CT=12, WT=8-1=7? Wait: WT = TAT - BT = (12-1) - 4 = 7.
- P3: start=12, CT=14, WT = (14-2) - 2 = 10.
Average WT = (0+7+10)/3 = 5.67 ms.
Now compare with SJF: P1(8), P2(4), P3(2). If SJF non-preemptive, after P1 (8), P3 (2) then P2 (4): P1 WT=0, P3 WT=8-2=6?, actually start of P3 = 8, WT = (10-2)-2 = 6. P2 start=10, WT = (14-1)-4 = 9. Avg WT = (0+6+9)/3 = 5.0. Slightly better, but convoy effect is small because burst times are similar. If P1 were much larger, difference would be stark.
Q05 of 05JUNIOR
Does FCFS cause starvation? Explain.
ANSWER
No, FCFS does not cause starvation because every process will eventually reach the head of the queue and execute. There is no priority mechanism that could perpetually bypass a process. However, a process with a very long burst can cause other processes to wait an extremely long time (effectively bounded but high). This is sometimes confused with starvation, but starvation implies indefinite postponement, which cannot happen under FCFS.
01
Explain the convoy effect in FCFS scheduling and show it with an example.
SENIOR
02
Is FCFS preemptive or non-preemptive? What are the implications?
JUNIOR
03
When would you choose FCFS over other scheduling algorithms in a production system?
SENIOR
04
Calculate average waiting time for FCFS with processes P1(AT=0,BT=8), P2(AT=1,BT=4), P3(AT=2,BT=2).
SENIOR
05
Does FCFS cause starvation? Explain.
JUNIOR
FAQ · 5 QUESTIONS
Frequently Asked Questions
01
Does FCFS cause starvation?
No — every process eventually gets the CPU since there is no priority-based preemption. However, average waiting time can be very high (effectively long waits for short processes), which is sometimes confused with starvation.
Was this helpful?
02
Can FCFS be preemptive?
No — by definition, FCFS is non-preemptive. If you add preemption, it becomes Round Robin (with a time quantum) or priority-based scheduling.
Was this helpful?
03
Is FCFS the same as FIFO scheduling?
Yes, for processes with the same arrival order. FIFO refers to the queue discipline (First In, First Out); FCFS is the scheduling policy built on that queue.
Was this helpful?
04
How does FCFS handle processes arriving at the exact same time?
If two processes have identical arrival times, tie-breaking is typically by process ID. The scheduler can choose any order, but FCFS assumes a stable ordering — the exact choice does not affect the algorithm's definition.
Was this helpful?
05
Why is FCFS still taught if it's rarely used in modern OS?
Because it is the simplest scheduling model, serving as a baseline for evaluating all other algorithms. Understanding FCFS builds intuition for trade-offs around waiting time, fairness, and the convoy effect.