Processes, threads and context switches

1 min read

Cores run code in parallel: 8 cores run 8 instruction streams at the same instant. With hyperthreading (SMT) each core presents two logical processors, so an 8-core CPU shows as 16, and Environment.ProcessorCount counts those. The second thread is not extra compute. It fills slots the first leaves idle, for example while it waits on memory.

Process and thread

A process is a running program with its own memory. A thread is a unit of scheduling inside it. Threads share the process’s memory, and each has its own stack and instruction pointer. The OS scheduler decides which thread runs on which core.

Context switches

There can be far more threads than cores. With 4 cores and 400 threads, the OS gives each thread a few milliseconds, saves its state and switches. Only 4 run at any instant. Switching costs registers and caches, so past a point, more threads add overhead, not speed, which is why runtimes use a thread poolThe thread poolA set of reusable worker threads that take jobs from a queue.Opens in a new tab.

Four cores each run one thread. The other threads wait, and the OS swaps them in and out every few milliseconds. RUNNING WAITING core 1 thread A core 2 thread B core 3 thread C core 4 thread D thread E thread F thread G thread H ... 400 swap
4 cores run 4 threads at a time. The OS swaps the others in and out.

The .NET process

A .NET app is one OS process by default, with many threads: thread pool workers, GC threads, a finalizer thread, the main thread and any you create. Because they share memory, passing an object between threads passes a reference, and shared mutable state needs locks (see synchronization primitivesSynchronization primitives and concurrent collectionsWhat to use when several threads touch the same data.Opens in a new tab). More than one process comes only from deployment, such as worker services or load balancing.