liveBook · Manning

Context switching

As explained in Learn Concurrent Programming with Go

A context switch saves one task's execution state and restores another's so processor execution can move between tasks, threads, or goroutines.

Context switching moves CPU execution from one job or thread to another. The current execution state is saved, the next state is loaded, and the interrupted work can later resume. On a single CPU, repeated switches make multiple tasks appear to run at once; on multiple CPUs, tasks may also run truly in parallel. section 2.1 section 2.4

The saved state is the process context block (PCB), which holds details needed to resume work, including the program counter, CPU registers, and memory information. Saving and restoring that state adds overhead to every switch, so switching enables responsiveness but is not free. section 2.1

Scheduling determines when execution changes hands:

  • For kernel-level threads, the operating system keeps each thread’s registers, stack, and state, then intervenes to choose the next runnable thread. section 2.3.2
  • Preemptive OS scheduling can use clock interrupts to stop a kernel thread after its CPU time and switch to another thread from the run queue. section 2.3.3
  • A blocking I/O operation can also prompt a switch, allowing a single processor to give another job time while the first waits. section 2.4
  • User-level threads shift scheduling and context switching into an application runtime, which maintains state for each thread without OS intervention. section 2.3.2

User-level switching is faster than kernel-level switching because the process can change execution without entering the kernel. This avoids the OS scheduling intervention and can avoid flushing the CPU cache, but it also makes the runtime responsible for tracking and scheduling its own threads. section 2.3.2

Giving a goroutine a chance to run

Starting `sayHello` with `go` creates a goroutine, but `main` can terminate before it runs. Calling `runtime.Gosched()` asks the Go scheduler to yield execution, increasing the chance that `sayHello` prints `Hello` before `Finished`. It does not guarantee that result: the scheduler may select `main` again, so concurrent code must not depend on a particular next goroutine. section 2.3.3

Figure 2.11 Context switching in Go requires user-level events.

The figure distinguishes OS clock-driven switching from Go’s user-level scheduler, which needs events such as goroutine creation, system calls, or synchronization to run. section 2.3.3

How Learn Concurrent Programming with Go covers it

How deep it goes
Defines saved process state, switching overhead, kernel and user-level management, and Go yield behavior without detailing scheduler selection algorithms.
Examples
Uses a text-search job lifecycle and a Go `sayHello` program calling `runtime.Gosched()`.
What it assumes
Introduces scheduling and thread-management distinctions in plain terms while using Go goroutines and `runtime.Gosched()` as the practical setting.
What you can do after
Evaluate/understand why concurrent work appears interleaved and why Go programs cannot rely on a chosen goroutine running next.
How it connects
Connects context switching to scheduling, concurrency, parallelism, kernel-level threads, user-level threads, goroutines, and blocking I/O.

Also explained in

Compare how 9 books explain context switching →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Learn Concurrent Programming with Go. The section links point to the parts of the book it draws on.