The Big Picture: Who Goes First?
At an airport, a passenger with a flight in 20 minutes may skip the queue. Everyone else waits in order. Priority works the same way for threads: a more important thread gets a core before a less important one.
Windows gives every thread a priority number from 0 to 31. A bigger number means more important.
31 ┐
.. │ REAL-TIME range (16–31) ← very rare; can starve the whole PC
16 ┘
15 ┐
.. │ DYNAMIC range (1–15) ← all normal programs live here
1 ┘
0 Zero-page thread (one special system thread; nothing else)
The scheduler's rule: the highest-priority ready thread runs. A priority-8 thread never runs while a priority-9 thread is ready and a core is needed.
5.1 Priority Levels (Windows Priority Classes)
A program does not usually pick a raw number. It picks two things:
- A priority class for the whole process (a "base level").
- A relative thread priority for each thread (a small step up or down from the base).
Process priority classes:
| Priority class | Base priority number | Where you see it |
|---|---|---|
| Idle (Low) | 4 | Background tools that should never slow you down |
| Below Normal | 6 | Lower than usual |
| Normal | 8 | Almost every program |
| Above Normal | 10 | Slightly more important |
| High | 13 | Important tools; use carefully |
| Realtime | 24 | Dangerous; needs special rights (Section 5.3) |
Task Manager shows "Low" for Idle. Windows 11 also has a "Background" mode for some system tasks (memory and I/O priority are lowered too).
Relative thread priority (the step inside the class):
| Thread priority | Meaning |
|---|---|
| Idle | Lowest in the class |
| Lowest | Two below normal |
| Below Normal | One below |
| Normal | Same as the process's base |
| Above Normal | One above |
| Highest | Two above |
| Time Critical | Top of the class (for dynamic classes this is 15; for Realtime it is 31) |
The final number = process class base + the thread's step. For example, a Normal-class process (base 8) with a thread set to Above Normal gives priority 9. A thread in a Normal-class process set to Time Critical gets 15.
Process class Normal (base 8)
Idle → special low value
Lowest → 6
Below Normal → 7
Normal → 8 ← default for most threads
Above Normal → 9
Highest → 10
Time Critical → 15
Changing priority:
| How | Notes |
|---|---|
| Task Manager → Details → right-click process → Set priority | Changes the process class. Reverts when the process ends |
PowerShell: (Get-Process notepad).PriorityClass = 'BelowNormal' | Same idea |
start /belownormal program.exe in Command Prompt | Starts at that class |
SetPriorityClass, SetThreadPriority | The calls programs use |
Good habit: If a long job (a video render, a big backup) makes your PC feel slow, run it at Below Normal or Idle. It will still finish, but the mouse and windows stay lively.
5.2 Priority Boosting
What it is: Windows can temporarily raise a thread's priority above its base to help it respond faster or avoid being stuck. This dynamic boost only happens for threads in the dynamic range (1–15), never for real-time ones.
Common boosts:
| Event | Why the boost |
|---|---|
| Thread finishes waiting for I/O (disk, network, keyboard, mouse) | So it can react quickly. The size depends on the device; for example keyboard or mouse input gives a bigger boost than a disk |
| Thread of the foreground window | Makes the app you use feel snappier. Its quantum can also be longer |
| GUI thread wakes up because of a window message | Keeps the interface responsive |
| Thread has been waiting in Ready for too long | Anti-starvation (see below) |
| Thread released a lock that others wait for | Helps threads work through shared locks |
How the boost fades: Each time the boosted thread uses up a full quantum, its priority drops by one level, until it is back at its base. A boost never raises a thread above 15.
Priority
11 │ ● (boost after waiting for the keyboard)
10 │ ●
9 │ ●
8 │ ───●─────────●─────●────● ← base priority 8
└──────────────────────────► time (each ● = one quantum used)
Anti-starvation: the "balance set manager". A low-priority thread might never get a core if busier threads always win. Windows has a helper that checks about once per second for threads that have been Ready for around 4 seconds or more. It gives them a short, big boost (to priority 15) and a double quantum so they can finish a bit of work. After that, they return to normal. This keeps even low-priority threads moving.
You can turn dynamic boost off per process with the SetProcessPriorityBoost call. It is rarely needed.
5.3 Real-Time Priority
What it is: Priorities 16 to 31 are the real-time range. Threads here are not boosted or lowered by Windows. They stay at a fixed priority.
Real-time does NOT mean "faster". In computing, "real-time" means a task must respond within a guaranteed time limit, such as an audio buffer, a robot arm or a medical device. Windows is not a true real-time operating system, but this range gets as close as it can.
Dangers: A real-time thread can beat everything that Windows itself needs to run, including threads that handle your keyboard, mouse and disk. If a real-time thread loops forever, the PC can freeze solid. Because of this:
- Setting the Realtime priority class needs special user rights (the "Increase scheduling priority" right; administrators have it).
- Without that right, Windows quietly lowers the request to High.
- Task Manager and the OS warn you.
Who uses real-time priority: some audio software and drivers, certain industrial or lab software, and parts of Windows itself (for example, some critical system threads). Normal desktop software should never use it.
Rule: Use High at most, and only for short, well-behaved work. Leave Realtime to specialists.
Also: MMCSS. For multimedia such as audio and video, Windows has a helper called MMCSS (Multimedia Class Scheduler Service). A program registers its thread, and MMCSS gives it a boosted priority for a few milliseconds each cycle in a controlled way. This is safer than choosing real-time yourself.
5.4 Priority Inversion Problem
What it is: Priority inversion is a bug-like situation where a high-priority thread is stuck waiting for a low-priority thread, and a medium-priority thread keeps stealing the CPU. So the high-priority thread is effectively slowed by someone less important.
Here is the story with three threads:
| Thread | Priority | What it does |
|---|---|---|
| H | High | Needs a lock (mutex) |
| M | Medium | Just busy calculating, does not need the lock |
| L | Low | Holds the lock right now |
time ──►
L (low) ██ takes lock ██ ─preempted─ ── ██ releases lock
H (high) ▒▒▒▒ wants lock → BLOCKED ▒▒▒▒▒▒▒▒▒▒▒▒▒▒ ██ finally runs
M (medium) ████████████████████████████
▲
M runs instead of L, so L cannot finish and cannot release the lock.
H waits for L. L waits for M. The ranking is turned upside down.
Why it hurts: H should be the most important. But M, which is less important, delays H without ever touching the lock.
Famous case: In 1997 the Mars Pathfinder probe kept resetting itself because of exactly this bug. The fix was to turn on priority inheritance.
How it is solved:
| Method | Idea |
|---|---|
| Priority inheritance | While H waits for a lock held by L, L temporarily gets H's priority. Now M cannot push L aside, L finishes and releases the lock |
| Priority ceiling | The lock has a ceiling; any thread that holds it runs at that high priority |
| Avoid long locks | Keep locks short and do not hold them while doing slow things |
What Windows does: Windows has no general priority inheritance for ordinary locks (such as a mutex or critical section). Instead it uses a cheaper trick to break the starvation. As seen in Section 5.2, the balance-set helper boosts any thread that has been Ready for several seconds. L eventually gets a boost, finishes, and frees the lock. It is slow (seconds) but it breaks the deadlock-like stall. You should still design to avoid inversion: keep high- and low-priority threads from sharing locks where possible.
Summary
| Term | Plain meaning |
|---|---|
| Priority 0–31 | Bigger number runs first |
| Dynamic range 1–15 | Normal programs; Windows may boost and drop |
| Real-time range 16–31 | Fixed; can starve the OS; needs special rights |
| Priority class | A process-level base (Idle 4, Below Normal 6, Normal 8, Above Normal 10, High 13, Realtime 24) |
| Relative thread priority | A step up or down from the class base |
| Boost | A temporary lift (after I/O, for the foreground window, or against starvation) |
| Balance-set manager | Boosts long-starved ready threads about once a second |
| MMCSS | Safe way for audio/video threads to get priority |
| Priority inversion | High waits on low while medium runs |
| Priority inheritance | Low borrows high's priority to finish quickly |