This trace follows the actual state transitions behind the companion Processes, Threads, and the Cost of Sharing. Each step below names its concrete inputs; values illustrate the mechanism and vary across implementations.
Step 1: Place work in runnable state
A process is a protected resource container with an address space and operating-system-managed resources. A thread is an execution stream with its own program counter, registers, and stack. Threads in one process normally share code and heap memory, which makes communication cheap but coordination necessary.
Step 2: Select a thread to run
When a thread blocks on I/O, the scheduler may run another runnable thread. A context switch saves enough state to resume later and changes which execution stream receives CPU time. Creating a thread does not guarantee it runs immediately; scheduling policy, contention, and available cores influence when it progresses.
Step 3: Save and restore context
When a running thread blocks, the scheduler can run another eligible thread; threads in one process share address space, so they must coordinate updates to shared invariants.
Checkpoint: When a running thread blocks, the scheduler can run another eligible thread; threads in one process share address space, so they must coordinate updates to shared invariants. Confirm this state before advancing to Block or wake on an event.
Step 4: Block or wake on an event
Threads share mutable state, so unsynchronized access can produce races even on a single core through interleaving. Processes provide stronger isolation but require explicit communication and often more setup. More threads can increase context switching, memory use, and contention instead of increasing throughput.
Step 5: Coordinate shared memory
A server creates one thread per connection and suddenly slows down under a large idle-client load. Name two resource costs and one alternative concurrency model to evaluate.
The trace is done when this check holds: A server creates one thread per connection and suddenly slows down under a large idle-client load. Compare the outcome against the companion article before making a performance claim.
Hardware, runtime, and observability notes
When tracing Trace: Processes, Threads, and the Cost of Sharing in a live production environment (subsystem: scheduling, primary layer: kernel), keep the following step-level cost model and diagnostic checklist in mind:
- Step 1 (kernel): Place work in runnable state — verifies state invariants before advancing the execution pointer.
- Step 2 (kernel): Select a thread to run — verifies state invariants before advancing the execution pointer.
- Step 3 (kernel): Save and restore context — verifies state invariants before advancing the execution pointer.
- Step 4 (kernel): Block or wake on an event — verifies state invariants before advancing the execution pointer.
- Step 5 (kernel): Coordinate shared memory — verifies state invariants before advancing the execution pointer.
Every transition across the kernel boundary carries both a direct CPU/memory cost (cache-line fills, descriptor lookups, lock acquisitions, or context switches) and a tail-latency queueing risk under contention. To verify this trace on your own service, capture latency histograms and hardware/kernel counters across each step boundary, compare cold-cache versus warm-cache execution paths, and confirm that error or timeout branches release all acquired descriptors, locks, and buffers cleanly.