The Big Picture: A Thread's Day
A thread is never just "on". At every moment it is in exactly one state: a label that says what it is doing right now. Think of a customer in a shop: in the queue, at the counter, waiting for the item to arrive from the back room, or gone home.
Windows has more fine-grained states internally, but they fit into four easy groups. We learn the simple four first, then add the extra ones Windows uses.
┌─────────┐ scheduler picks it ┌─────────┐
│ READY │ ──────────────────────► │ RUNNING │
└─────────┘ └─────────┘
▲ ▲ │ │
│ └── quantum over / preempted ──┘ │ function returns
│ │ or ExitThread
│ wait is over must wait ▼
┌─────────┐ ◄───────────────────────┘ ┌────────────┐
│ WAITING │ │ TERMINATED │
└─────────┘ └────────────┘
4.1 Ready
What it is: A Ready thread is able to run and wants the CPU, but no core is free yet (or a more important thread is using it). It sits in the ready queue.
Windows keeps one ready queue per priority level (0 to 31). When a core becomes free, the scheduler looks at the highest non-empty queue first.
How a thread becomes Ready:
- It was just created and is set to run.
- Its wait ended (the file arrived, the lock was released).
- It was preempted (a higher-priority thread took its core, or its quantum ended).
Why this matters to you: Many threads sitting in the Ready state at once means the CPU is overloaded. You can watch it with the counter \System\Processor Queue Length in Performance Monitor. A common rule of thumb is that a value that stays above about 2 per logical processor suggests the CPU is a bottleneck.
4.2 Running
What it is: A Running thread is executing instructions on a core right now. Only as many threads can be Running as there are logical processors. On an 8-logical-processor PC, at most 8 threads run at the same instant.
A Running thread leaves that state for one of these reasons:
| Reason | Next state |
|---|---|
| Its quantum ends and an equal-priority thread is waiting | Ready |
| A higher-priority thread becomes ready (preemption) | Ready |
| It must wait (disk, network, lock, sleep) | Waiting |
| It finishes | Terminated |
While it runs, a thread can run in two modes (covered in the chapters on the OS):
- User mode: running the program's own code.
- Kernel mode: running inside Windows on the program's behalf, for example during a file read.
Task Manager's CPU graph can show "kernel times" (a red line in Resource Monitor) so you can see how much time is spent in each.
4.3 Waiting / Blocked
What it is: A Waiting thread (some books say Blocked) cannot run because it is waiting for something. It uses no CPU while it waits. The scheduler ignores it completely.
What a thread can wait for:
| Wait for | Example |
|---|---|
| I/O to finish | Reading a file, waiting for a network packet |
| A lock (mutex, critical section) | Another thread holds it (Section 7) |
| An event or semaphore | "Data is ready" signal |
| A timer | Sleep(1000) |
| Another thread or process to end | WaitForSingleObject(handle, ...) |
| A page fault to be fixed | The needed memory page must be loaded from disk (Chapter 3) |
How it works: the thread asks Windows to wait on a dispatcher object (a kernel object that can be "signalled", such as an event). Windows puts the thread on that object's wait list and picks another thread to run. When the object is signalled, the thread moves back to Ready.
Thread A: ReadFile(...) ──► state: WAITING (disk working)
core 0 now runs thread B instead
Disk done ──► interrupt ──► A moves to READY ──► later RUNNING again
This is why having many threads is fine when most are waiting: they cost memory but almost no CPU.
Wait reasons. Windows records why a thread waits (for example Executive, UserRequest, WrQueue, DelayExecution, WrPageIn). In PowerShell:
(Get-Process -Name explorer).Threads |
Select-Object -First 8 Id, ThreadState, WaitReason, PriorityLevelYou will see most threads showing Wait with a reason. Very few show Running.
Stuck threads. A thread that waits forever (because the thing it waits for never happens) is "hung". A program whose UI thread is stuck like this shows "Not Responding". Resource Monitor can help (Section 8.5).
4.4 Terminated
What it is: A Terminated thread has finished. It will never run again. See Section 2.4 for how a thread ends.
What remains:
- The thread's stack is freed.
- The kernel's thread object lingers until all handles to it are closed. This lets other code read the exit code and wait on it.
- Anything waiting for this thread to end is moved to Ready.
When the last thread in a process ends, the process ends too.
4.5 State Transition Diagram
Windows has extra internal states that sit between Ready and Running. You can see them in tools and in the kernel's documentation. Here is the full list:
| State | Plain meaning |
|---|---|
| Initialized | The thread object is being created. Not yet usable. |
| Ready | Can run; waiting in a ready queue for a free core |
| Standby | Chosen as the next thread for a particular core; waiting for the switch to happen. Only one thread per core can be in Standby |
| Running | Executing on a core now |
| Waiting | Blocked on something |
| Transition | Ready to run, but its kernel stack has been paged out to disk. It must be brought back first |
| Terminated | Finished |
Here is the full picture:
┌─────────────┐
│ INITIALIZED │ (created)
└──────┬──────┘
│ made runnable
▼
┌─────────────┐ ◄────────── wait is over (stack in memory)
│ READY │ ◄────────── preempted / quantum ended
└──────┬──────┘ ◄──────┐
│ scheduler │ stack paged back in
│ picks a core │
▼ │
┌─────────────┐ ┌────┴───────┐
│ STANDBY │ │ TRANSITION │
└──────┬──────┘ └────────────┘
│ switch happens ▲ wait is over, but kernel
▼ │ stack was paged out
┌─────────────┐ must wait ┌──┴──────────┐
│ RUNNING │ ──────────► │ WAITING │
└──────┬──────┘ └─────────────┘
│ finished
▼
┌─────────────┐
│ TERMINATED │
└─────────────┘
Reading it: The loop that matters in daily life is Ready → Standby → Running → (Ready or Waiting) → Ready ... over and over, thousands of times per second. Initialized and Terminated happen once per thread. Transition is rare and only appears when memory is tight.
A typical life:
Initialized → Ready → Standby → Running → Waiting (disk) → Ready
→ Standby → Running → Ready (quantum ended) → Standby → Running → Terminated
Where to see states:
| Tool | What it shows |
|---|---|
PowerShell (Get-Process -Id <pid>).Threads | ThreadState (Running, Wait, Ready, Standby, Transition, Terminated...) and WaitReason |
| Process Explorer (Sysinternals, a free Microsoft tool) | Threads tab with state and start address |
Performance Monitor \Thread(*)\Thread State | A number for each thread's state (for example 2 means Running, 5 means Waiting) |
Performance Monitor \System\Processor Queue Length | How many threads are ready and waiting |
Note: Do not worry if tool labels differ a little from the textbook names. Tools often round states into simpler words.
Summary
| State | Plain meaning |
|---|---|
| Initialized | Being created |
| Ready | Can run, waiting for a core |
| Standby | Picked as next on a core, switching in |
| Running | Executing on a core now |
| Waiting | Blocked; uses no CPU until the wait ends |
| Transition | Ready, but its kernel stack is on disk |
| Terminated | Finished |
| Processor Queue Length | A count of Ready threads; a quick CPU-overload sign |