Linux nice values range -20 (highest) to +19 (lowest) – lower numeric means higher priority.
Production insight: priority inversion can cause real-time tasks to miss deadlines if a high-priority task waits on a low-priority lock.
Biggest mistake: confusing numeric priority direction – always verify with ps -eo pid,pri,nice.
✦ Definition~90s read
What is Priority Scheduling and Aging?
Priority scheduling is a CPU scheduling algorithm where each process is assigned a priority number, and the scheduler always runs the highest-priority ready process. It exists to enforce differential service—critical system tasks (e.g., hardware interrupts, real-time control loops) must run before background jobs.
★
Priority scheduling is like a hospital triage system — critical patients are seen first regardless of arrival order.
In practice, priorities are typically integers (0–255 or 0–139 in Linux), with lower numbers meaning higher priority. The algorithm can be preemptive (current process is forcibly descheduled when a higher-priority process becomes ready) or non-preemptive (process runs to completion or yields).
Priority scheduling is ubiquitous in real-time and embedded systems, but it's rarely used alone in general-purpose OSes due to its fatal flaw: starvation. Low-priority processes may never run if higher-priority tasks continuously occupy the CPU. To mitigate this, aging gradually increases a process's priority over time, ensuring eventual execution.
The alternative is multilevel queue scheduling, which partitions processes into separate priority bands with different scheduling policies per queue—common in modern kernels like Linux's Completely Fair Scheduler (CFS) and Windows' hybrid scheduler. You should not use pure priority scheduling for interactive or throughput-oriented workloads; round-robin or CFS is better.
The algorithm's most infamous failure was the 1997 Mars Pathfinder mission, where a priority inversion bug caused system-wide resets. A low-priority meteorological data task held a mutex needed by a high-priority bus management task, while a medium-priority communications task preempted the low-priority holder.
The high-priority task starved, triggering the watchdog timer. Engineers fixed it by enabling priority inheritance—a protocol where a low-priority task temporarily inherits the priority of any higher-priority task waiting for its lock. This real-world disaster cemented priority inheritance as a mandatory feature in any priority-scheduled system using locks.
Plain-English First
Priority scheduling is like a hospital triage system — critical patients are seen first regardless of arrival order. The danger: low-priority patients (processes) might never be seen if high-priority ones keep arriving. Aging solves this by gradually increasing the priority of waiting processes — the longer you wait, the more important you become.
Priority scheduling is what your OS uses right now. Linux's nice values (-20 to +19), Windows' priority classes (0-31), Java's Thread.setPriority() — all are implementations of priority scheduling. The starvation problem is real: in early Unix systems before aging was implemented, background processes at low priority could wait hours or days before getting CPU time if the system was heavily loaded.
The solution — aging — is an example of a general algorithm design principle: make greedy choices less greedy over time by adjusting inputs. A low-priority process that has waited long enough becomes a high-priority process. The invariant being maintained is that no process waits forever, even if it regularly loses to higher-priority work.
Why Priority Scheduling Nearly Killed a Mars Rover
Priority scheduling assigns each process a numeric priority; the scheduler always runs the highest-priority ready process. The core mechanic is simple — but the consequences are not. In the Mars Pathfinder mission, a lower-priority data bus task was preempted by a higher-priority weather task, which in turn blocked on a mutex held by the data task. The result: a priority inversion that triggered a system reset.
Preemptive priority scheduling means a running process can be interrupted at any instant by a higher-priority process. This gives low latency for critical tasks but introduces starvation: low-priority processes may never run if higher-priority work keeps arriving. Priority inversion occurs when a high-priority task waits on a resource held by a low-priority task that is preempted by a medium-priority task — the high-priority task effectively inherits the low-priority task's place in line.
Use priority scheduling when you have clear urgency tiers — real-time control, audio processing, or interrupt handlers. But never deploy it without priority inheritance or a ceiling protocol. The Mars Pathfinder bug was fixed by enabling the priority inheritance protocol in the VxWorks kernel, a one-line change that prevented the inversion. Without that, the rover would have reset every few hours.
⚠ Priority Inversion Is Not a Theory
A medium-priority task can starve a high-priority task without ever blocking — it just keeps the CPU away from the low-priority task holding the lock.
📊 Production Insight
Teams using priority scheduling on embedded systems often miss that a mutex held by a low-priority task can stall a high-priority task indefinitely.
The symptom: a watchdog timer fires because the high-priority control loop misses its deadline, even though it's 'highest priority.'
Rule of thumb: any shared resource accessed by tasks of different priorities must use priority inheritance or a priority ceiling protocol — no exceptions.
🎯 Key Takeaway
Priority scheduling guarantees low latency for critical tasks but introduces starvation and inversion risks.
Always pair priority scheduling with a priority inheritance or ceiling protocol when tasks share resources.
Without inversion protection, a medium-priority task can effectively block a high-priority task — the Mars Pathfinder bug proved this is not theoretical.
thecodeforge.io
Priority Scheduling Algorithm
Priority Scheduling Implementation
The non-preemptive priority scheduler implemented here picks the highest-priority ready process (lower numeric value = higher priority). It uses a min-heap to manage ready processes efficiently. Processes are sorted by arrival time first; then at each tick, all processes that have arrived are pushed onto the heap. The scheduler always runs the process with smallest priority number. This is a classic batch-oriented approach – suitable when tasks are short and infrequent, but dangerous in interactive systems where unpredictability can cause missed deadlines.
priority_scheduling.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
32
33
34
35
36
37
38
39
import heapq
defpriority_non_preemptive(processes: list[dict]) -> list[dict]:
"""
processes: {pid, arrival, burst, priority}
Lower priority number = higher priority (1 = highest).
"""
procs = sorted(processes, key=lambda p: p['arrival'])
results = []
time = 0
heap = [] # (priority, arrival, process) — min-heap
i = 0while i < len(procs) or heap:
while i < len(procs) and procs[i]['arrival'] <= time:
p = procs[i]
heapq.heappush(heap, (p['priority'], p['arrival'], p))
i += 1ifnot heap:
time = procs[i]['arrival']
continue
_, _, p = heapq.heappop(heap)
start = time
ct = start + p['burst']
tat = ct - p['arrival']
wt = tat - p['burst']
time = ct
results.append({**p, 'start': start, 'ct': ct, 'tat': tat, 'wt': wt})
return results
processes = [
{'pid':'P1','arrival':0,'burst':10,'priority':3},
{'pid':'P2','arrival':1,'burst':1, 'priority':1},
{'pid':'P3','arrival':2,'burst':2, 'priority':4},
{'pid':'P4','arrival':3,'burst':1, 'priority':5},
{'pid':'P5','arrival':4,'burst':5, 'priority':2},
]
results = priority_non_preemptive(processes)
for r insorted(results, key=lambda x: x['pid']):
print(f"{r['pid']}: priority={r['priority']}, WT={r['wt']}, TAT={r['tat']}")
Output
P1: priority=3, WT=0, TAT=10
P2: priority=1, WT=9, TAT=10
P3: priority=4, WT=17, TAT=19
P4: priority=5, WT=19, TAT=20
P5: priority=2, WT=7, TAT=12
📊 Production Insight
Non-preemptive priority scheduling can cause high-priority tasks to wait for a low-priority task that has already started.
If low-priority task holds a shared lock, priority inversion occurs – the system stalls.
Rule: use preemptive priority scheduling for any interactive or real-time workload; reserve non-preemptive only for batch.
🎯 Key Takeaway
Priority scheduling needs a clear convention on numeric direction.
Non-preemptive mode can cause unexpected delays for high-priority tasks.
Always document and verify priority scheme with system tools.
Starvation and Aging
Starvation occurs when low-priority processes wait indefinitely because high-priority ones keep arriving.
Aging solution: increase the priority of a process by 1 every T time units it waits. Eventually every process becomes highest priority and executes. The choice of T is critical – too large and starvation persists, too small and the priority system loses its intended differentiation. A common starting point: T = 5 * average burst time of all processes.
aging.pyPYTHON
1
2
3
4
5
6
7
8
9
10
11
12
defapply_aging(processes: list[dict], time: int, aging_interval: int = 5) -> None:
"""Boost priority of waiting processes every aging_interval time units."""for p in processes:
if p.get('waiting', 0) > 0and p['waiting'] % aging_interval == 0:
p['priority'] = max(1, p['priority'] - 1) # lower number = higher priority# Demonstration: process stuck at priority 10, aging every 5 time unitsprint('Priority progression with aging:')
priority = 10for t inrange(0, 51, 5):
print(f't={t:3}: priority={priority}')
priority = max(1, priority - 1)
Output
Priority progression with aging:
t= 0: priority=10
t= 5: priority=9
t= 10: priority=8
t= 15: priority=7
t= 20: priority=6
t= 25: priority=5
t= 30: priority=4
t= 35: priority=3
t= 40: priority=2
t= 45: priority=1
t= 50: priority=1
📊 Production Insight
Aging increases priority gradually – but if aging interval is too slow, starvation persists.
If too fast, low-priority tasks become high-priority too quickly, defeating the purpose.
Production rule: choose aging interval based on expected wait time (e.g., 5 times average burst time).
🎯 Key Takeaway
Aging guarantees eventual execution but needs careful interval tuning.
Without aging, low-priority processes can wait indefinitely.
Memo: wait time + aging interval = upper bound on starvation.
thecodeforge.io
Priority Scheduling Algorithm
Multilevel Queue Scheduling
Modern OSes use multilevel queues – separate queues for different process types (real-time, interactive, batch), each with its own scheduling algorithm. Processes are permanently assigned to a queue based on their type. Multilevel Feedback Queue (MLFQ) adds mobility: processes move between queues based on behaviour – CPU-bound processes drift to lower priority, I/O-bound stick to higher priority. This is what Linux and Windows implement underneath (with dynamic priority boosts for interactive tasks).
MLFQ prevents starvation by periodically boosting all processes to the top queue (every ~200ms in Linux). This ensures every process gets a time slice eventually.
🔥Real OS Priority
Linux uses priority -20 (highest) to +19 (lowest via 'nice'). Windows uses 0-31. Both use preemptive priority scheduling with time quanta within priority levels. Real-time processes get highest priority and can preempt anything.
📊 Production Insight
In MLFQ, CPU-bound processes get demoted – but if a batch job becomes interactive, it may be stuck at low priority.
Linux prevents this with periodic priority boost; Windows boosts foreground UI threads.
Rule: monitor process priority drifts with ps -eo pid,pri,nice,cls to identify unexpected demotions.
🎯 Key Takeaway
MLFQ adapts to process behaviour – but can starve CPU-bound processes without periodic boost.
Real OSes combine priority with time quanta to ensure fairness.
Check nice and priority levels to confirm correct scheduling class.
Preemptive vs Non-Preemptive Priority Scheduling
In non-preemptive priority scheduling, once a process starts running, it continues until it blocks or finishes – even if a higher-priority process arrives in the meantime. This can cause high-priority tasks to miss deadlines. In preemptive priority scheduling, the running process is immediately interrupted when a higher-priority process becomes ready. Preemptive ensures that the highest-priority ready process always runs, but it adds context-switch overhead and requires careful synchronization for shared resources.
Real-time systems (e.g., VxWorks, RT-Linux) use preemptive priority scheduling. General-purpose OSes use a hybrid: preemptive with time quanta, where priority determines the next process but CPU-bound tasks eventually get demoted.
📊 Production Insight
Preemptive scheduling is required for real-time systems; non-preemptive is simpler but can cause priority inversion.
Context-switch overhead increases with higher preemption rates – amortize by using larger time quanta for low-priority tasks.
Rule: if a high-priority task misses its deadline, check preemption configuration first.
🎯 Key Takeaway
Choose preemptive for responsiveness, non-preemptive for simplicity.
Preemptive incurs context-switch overhead – measure before deciding.
For shared resources, combine preemption with priority inheritance to avoid inversion.
When to Use Preemptive vs Non-Preemptive
IfSystem has hard real-time deadlines (audio, control systems)
→
UseUse preemptive priority scheduling with priority inheritance on all locks.
IfTasks are short (< 1 ms) and cooperative
→
UseNon-preemptive can work and avoids synchronization complexity.
IfMixed workload: some real-time, some batch
→
UseUse MLFQ (preemptive) and assign real-time tasks to highest queues with fixed priority.
Priority Inversion – The Mars Pathfinder Bug
In 1997, the Mars Pathfinder rover, running VxWorks, experienced repeated system resets. The root cause was priority inversion: a high-priority data bus task blocked waiting for a mutex held by a low-priority meteorological task. A medium-priority communications task ran continuously, preventing the low-priority task from releasing the mutex. The high-priority task starved, causing a hardware watchdog to reset the system.
The fix was to enable priority inheritance on the mutex: when a high-priority task blocks on a lock, the lock-holding low-priority task temporarily inherits the higher priority, allowing it to run and release the lock quickly. This is now standard practice in real-time operating systems.
Mental Model
Priority Inheritance Visual
Think of priority inheritance as a temporary promotion for the lock holder – they get a 'badge' of the higher priority until they release the lock.
Without inheritance: low-priority holder stays low, gets preempted by medium tasks → high-priority starves.
With inheritance: low-priority holder temporarily runs at high priority → releases lock fast → returns to original priority.
This is a simple, local fix that prevents cascading failures in real-time systems.
📊 Production Insight
Priority inversion can cause total system failure in real-time systems – it's not just a theoretical problem.
Priority inheritance adds minimal overhead but requires explicit support in kernel and libraries.
Rule: enable priority inheritance (PI) on all mutexes shared across priority levels; test with worst-case lock contention patterns.
🎯 Key Takeaway
Priority inversion is the #1 bug in priority-based real-time systems.
Always use priority inheritance or ceiling protocols for shared resources.
The Mars Pathfinder bug exists because PI was disabled by default – check your OS config.
Priority Scheduling in C – The Brutal Implementation
You want a priority scheduler. Not a textbook diagram, but actual C code that runs. Here's the thing: every production scheduler I've seen wraps this logic in a sorted queue or a heap, not a linear scan. But let's walk the naive path first so you understand the perf trap.
The algorithm is disgusting simple: maintain a queue of process control blocks (PCBs). On each scheduling decision, scan the ready queue for the highest priority process. In non-preemptive mode, you run it to completion. In preemptive, you check after each timer tick whether a higher priority process arrived.
Don't use bubble sort on the queue — that's O(n) per insertion if you keep it sorted. A binary heap gives O(log n) inserts and O(1) peek. Your scheduler will live in the kernel; every microsecond counts. The code below is a stripped-down demo for non-preemptive priority scheduling. It assumes lower number = higher priority because that's what Unix nice values do.
PriorityScheduler.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
// io.thecodeforge — dsa tutorialimport java.util.*;
classProcess {
int pid, burstTime, priority;
Process(int pid, int bt, int pri) {
this.pid = pid; this.burstTime = bt; this.priority = pri;
}
}
publicclassPriorityScheduler {
publicstaticvoidmain(String[] args) {
List<Process> queue = Arrays.asList(
newProcess(1, 4, 2),
newProcess(2, 2, 1),
newProcess(3, 6, 3)
);
// sort by priority (lowest first), then FCFS
queue.sort(Comparator.comparingInt(p -> p.priority));
int time = 0;
for (Process p : queue) {
System.out.println("Time " + time + ": P" + p.pid + " runs for " + p.burstTime + " units");
time += p.burstTime;
}
System.out.println("Total completion time: " + time);
}
}
Output
Time 0: P2 runs for 2 units
Time 2: P1 runs for 4 units
Time 6: P3 runs for 6 units
Total completion time: 12
⚠ Production Trap:
Sorting the queue each time is O(n log n) per dispatch. Use a priority queue (heap) for O(log n) insertion and O(1) extraction. Otherwise, you'll waste CPU cycles in the scheduler itself.
🎯 Key Takeaway
Priority scheduling is just sorting by priority. The perf comes from how you sort — use a heap, not a scan.
Starvation – The Silent Process Killer
Starvation happens when a low-priority process never gets CPU time because higher-priority processes keep arriving. It's not a bug — it's a design choice until you remember that some processes (like garbage collection, log flushers, or heartbeat monitors) run at low priority and are critical to system health.
The fix is aging: increment a process's priority as it waits. Every scheduler I've deployed adds a boost every N seconds. The Mars Pathfinder used this, but their bug was priority inversion, not starvation. Starvation is more subtle — it's a gradual degradation where your low-priority watchdog timer fires late and the system resets.
Aging doesn't solve priority inversion. But it does guarantee forward progress. Without it, your system will eventually hang on a process that never gets its turn. I've seen this in embedded systems where a background calibration task starves because the main loop never yields. The fix: track wait time and bump priority linearly or exponentially. The code below implements a basic aging simulation: every 3 time units, each waiting process gets its priority decreased (higher priority).
AgingSimulation.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
32
// io.thecodeforge — dsa tutorialimport java.util.*;
classProcess {
int pid, burstTime, priority, waitTime;
Process(int pid, int bt, int pri) {
this.pid = pid; this.burstTime = bt; this.priority = pri;
}
}
publicclassAgingSimulation {
publicstaticvoidmain(String[] args) {
List<Process> queue = newArrayList<>(Arrays.asList(
new Process(1, 4, 5), // low prioritynewProcess(2, 2, 1),
newProcess(3, 6, 2)
));
int time = 0;
while (!queue.isEmpty()) {
// age waiting processesfor (Process p : queue) {
p.waitTime++;
if (p.waitTime % 3 == 0) p.priority--; // boost every 3 units
}
queue.sort(Comparator.comparingInt(p -> p.priority));
Process current = queue.remove(0);
System.out.println("Time " + time + ": P" + current.pid + " (pri " + current.priority + ") runs");
time += current.burstTime;
}
}
}
Output
Time 0: P2 (pri 1) runs
Time 2: P3 (pri 2) runs
Time 8: P1 (pri 3) runs // note: priority boosted from 5 due to aging
🔥Senior Shortcut:
Aging threshold is system-specific. Start with a linear boost every 10 scheduler ticks. If your system has hard real-time constraints, use exponential backoff — but that's a separate nightmare.
🎯 Key Takeaway
Without aging, low-priority processes starve. Boost priority proportional to wait time to guarantee forward progress.
Gantt Charts: Why You Can't Trust a Pretty Timeline
Every textbook shows you a Gantt chart like it's a gift from God. Clean blocks, perfect ordering, zero ambiguity. Real systems don't work that way. You need Gantt charts to debug priority scheduling because without a visual timeline, you're guessing at which process starved or why a deadline blew up.
The Gantt chart exposes the truth: context switches are expensive, priority inversions hide in plain sight, and your pretty algorithm degrades under load. When you see a low-priority process getting ten milliseconds after a high-priority process runs for two seconds, you know aging isn't configured or quantum is wrong. The chart forces you to confront the scheduling reality, not the textbook ideal.
Build Gantt charts from your scheduler's event logs. Don't simulate them. Pull real timestamps. That's when you see why your system failed at 3 AM.
GanttPriorityExample.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
// io.thecodeforge — dsa tutorialimport java.util.*;
classProcess {
String name; int burst, priority;
Process(String n, int b, int p) {
name = n; burst = b; priority = p;
}
}
publicclassGanttPriorityExample {
publicstaticvoidmain(String[] args) {
List<Process> proc = Arrays.asList(
newProcess("P1", 8, 2),
newProcess("P2", 3, 1),
newProcess("P3", 5, 3)
);
// Non-preemptive priority (lower = higher priority)
proc.sort(Comparator.comparingInt(p -> p.priority));
int time = 0;
System.out.print("Gantt: ");
for (Process p : proc) {
System.out.print(p.name + "(" + time + "-" + (time + p.burst) + ") ");
time += p.burst;
}
System.out.println();
}
}
Output
Gantt: P2(0-3) P1(3-11) P3(11-16)
⚠ Visualization Trap:
Don't draw Gantt charts manually. Log start/stop timestamps from your scheduler. Real traces expose jitter and queue delays that static plans never show.
🎯 Key Takeaway
A Gantt chart from live scheduler logs reveals priority inversions and starvation before they kill your production system.
thecodeforge.io
Priority Scheduling Algorithm
Priority Inversion: The Bug That Brought Down Mars Pathfinder
In 1997, a $150 million Mars rover nearly died because of priority inversion. A high-priority science task was waiting for a mutex held by a low-priority task, while a medium-priority task preempted the low one. The high-priority thread starved, watchdog kicked, rover reset. That's the production cost of ignoring priority inversion.
The fix isn't more priority levels. It's priority inheritance. When a low-priority thread holds a resource a high-priority thread needs, temporarily boost the low thread's priority to the high thread's level. This blocks the medium-priority thread from sneaking in. Real-time OS kernels like VxWorks and RT-Linux implement this. Your custom scheduler? Probably not. And that's why your robot arm jams.
You don't need a Mars rover to hit this. Any multi-threaded system with shared resources and different priorities will reproduce it. Test for it explicitly.
Use priority inheritance protocol. Boost the low-priority holder's priority temporarily to the highest waiter's level. Many Java executors don't do this—you must implement it or use real-time Java.
🎯 Key Takeaway
Priority inversion isn't theoretical. It killed Mars Pathfinder until a priority inheritance patch was uploaded from Earth. Test your lock hierarchies.
● Production incidentPOST-MORTEMseverity: high
Mars Pathfinder – Priority Inversion That Crashed a Spacecraft
Symptom
The spacecraft would randomly reset itself, causing data loss and communication blackouts.
Assumption
Engineers assumed the issue was a hardware problem or a software memory corruption bug.
Root cause
A priority inversion scenario: a high-priority data bus task was blocked waiting for a low-priority meteorological task holding a mutex, while a medium-priority communications task prevented the low-priority task from releasing the mutex.
Fix
Enabled priority inheritance on the mutex so that when a high-priority task blocks, the low-priority task temporarily inherits the higher priority, allowing it to run and release the lock.
Key lesson
Priority inheritance should be enabled on all mutexes shared between tasks of different priorities.
Always test with worst-case priority scenarios, even if they seem unlikely.
Use aging or priority donation to prevent indefinite blocking in priority-based systems.
Production debug guideSymptom-Action Guide3 entries
Symptom · 01
Low-priority process shows 0% CPU for extended periods
→
Fix
Check priority with ps -eo pid,pri,nice,pcpu,cmd --sort=pri and look for processes with low nice values (high numbers) consuming no CPU.
Symptom · 02
System becomes unresponsive despite idle CPU
→
Fix
Verify if a high-priority process is stuck waiting on a resource held by a low-priority process using strace -p <pid> to see blocked syscalls.
Symptom · 03
Real-time task misses deadlines intermittently
→
Fix
Examine lock owners via /proc/lock_stat or enable priority inheritance in the scheduler (requires kernel support).
★ Quick Cheat Sheet: Priority Scheduling IssuesCommands and fixes for common priority-related problems.
Process stuck and never gets CPU−
Immediate action
Check priority and nice value
Commands
ps -eo pid,pri,nice,state,cmd --sort=pri
top -p <pid>
Fix now
Increase priority using renice -n <value> -p <pid> or add aging mechanism in scheduler.
Priority Scheduling in C – The Brutal Implementation
AgingSimulation.java
class Process {
Starvation – The Silent Process Killer
GanttPriorityExample.java
class Process {
Gantt Charts
PriorityInversionDemo.java
class LowTask extends Thread {
Priority Inversion
Key takeaways
1
Priority scheduling
always run the highest-priority ready process.
2
Lower priority number conventionally means higher priority (like OS nice values).
3
Starvation
low-priority processes may never execute — solved by aging.
4
Aging
increase priority by 1 every T wait units — guarantees eventual execution.
5
MLFQ (Multilevel Feedback Queue) combines priority with dynamic adjustment based on behaviour.
6
Priority inversion can crash real-time systems
use inheritance on all shared mutexes.
Common mistakes to avoid
3 patterns
×
Assuming higher numeric priority means higher scheduling priority
Symptom
Process with priority 20 gets more CPU than priority 1 – violates intended scheduling.
Fix
Always verify the direction: in Linux, lower nice value (-20) is highest priority. Define convention in project docs and verify with ps -eo pid,pri,nice.
×
Not implementing aging in priority scheduling
Symptom
Low-priority jobs never complete, accumulate, and eventually degrade overall system throughput.
Fix
Add an aging mechanism that periodically boosts waiting processes' priority by 1 every N time units. Start with N = 5 * average burst time.
×
Confusing preemptive and non-preemptive priority scheduling
Symptom
Higher-priority process arrives but does not preempt the running process; leads to missed deadlines.
Fix
Use preemptive priority scheduling for any interactive or real-time tasks. Reserve non-preemptive for short cooperative batch tasks only.
What is starvation in priority scheduling and how does aging solve it?
Q02SENIOR
Compare preemptive vs non-preemptive priority scheduling.
Q03SENIOR
What is Multilevel Feedback Queue scheduling?
Q04JUNIOR
In Linux, what do negative nice values indicate?
Q05SENIOR
Explain priority inversion and how priority inheritance fixes it.
Q01 of 05JUNIOR
What is starvation in priority scheduling and how does aging solve it?
ANSWER
Starvation occurs when low-priority processes never get CPU because higher-priority processes keep arriving. Aging solves this by gradually increasing the priority of waiting processes (e.g., by 1 every T time units). Eventually every process reaches the highest priority and executes, guaranteeing progress. The trade-off: too-fast aging diminishes priority differentiation; too-slow aging doesn't prevent starvation.
Q02 of 05SENIOR
Compare preemptive vs non-preemptive priority scheduling.
ANSWER
In non-preemptive, a running process continues until it blocks or finishes – even if a higher-priority process arrives. This simplifies synchronization but can cause high-priority tasks to miss deadlines. In preemptive, the running process is immediately interrupted when a higher-priority process becomes ready, ensuring the highest-priority ready process always runs. Preemptive is required for real-time systems but adds context-switch overhead and requires careful lock handling (priority inheritance).
Q03 of 05SENIOR
What is Multilevel Feedback Queue scheduling?
ANSWER
MLFQ uses multiple priority queues. Processes start in the top queue and are demoted to lower queues if they use their full time slice (CPU-bound). I/O-bound processes that block before the slice expire stay in high queues. The system periodically boosts all processes to the top queue to prevent starvation. This is the basis for Linux Completely Fair Scheduler (CFS) and Windows scheduling. It adapts to process behaviour dynamically.
Q04 of 05JUNIOR
In Linux, what do negative nice values indicate?
ANSWER
Negative nice values indicate higher priority (lower nice = higher priority, range -20 to +19). Changing to negative nice requires root privileges. For example, nice -n -10 ./process sets nice to -10, giving it higher scheduling priority. This is used for real-time or latency-sensitive tasks.
Q05 of 05SENIOR
Explain priority inversion and how priority inheritance fixes it.
ANSWER
Priority inversion occurs when a high-priority task (H) is blocked waiting for a resource held by a low-priority task (L), while a medium-priority task (M) preempts L. H starves because L cannot run. Priority inheritance temporarily boosts L's priority to H's when H blocks on L's lock, allowing L to run and release the lock quickly. After release, L returns to its original priority. This prevents indefinite blocking without sacrificing concurrency.
01
What is starvation in priority scheduling and how does aging solve it?
JUNIOR
02
Compare preemptive vs non-preemptive priority scheduling.
SENIOR
03
What is Multilevel Feedback Queue scheduling?
SENIOR
04
In Linux, what do negative nice values indicate?
JUNIOR
05
Explain priority inversion and how priority inheritance fixes it.
SENIOR
FAQ · 3 QUESTIONS
Frequently Asked Questions
01
What is the difference between priority scheduling and SJF?
SJF is actually a special case of priority scheduling where the priority is the inverse of burst time (shorter burst = higher priority). The starvation problem also applies to SJF for the same reason.
Was this helpful?
02
Can aging cause priority explosion?
Yes, if aging runs too fast, all processes quickly converge to highest priority, defeating the priority system. The aging interval must be tuned – typically 5–10 times the average burst time. Also cap priority to the highest level to avoid overflow.
Was this helpful?
03
Does Linux use priority scheduling?
Linux uses Completely Fair Scheduler (CFS) by default, which models CPU allocation as a virtual runtime but also incorporates nice values for priority weights. Additionally, real-time scheduling policies (SCHED_FIFO, SCHED_RR) use strict priority-based preemption for processes needing deterministic behaviour.