← Concepts

阅读中文版本

Cooperative Versus Preemptive Scheduling

Cooperative schedulers switch tasks only at yield points — cheap and predictable, but one selfish task stalls everything; preemptive schedulers force switches — robust but costlier.

concurrency

Definition

Cooperative multitasking relies on tasks voluntarily yielding at safe points: context switches are function calls, and correctness between yields is guaranteed. Preemptive multitasking interrupts tasks on timer or priority events regardless of their state: no task can monopolize the CPU, at the cost of preemption overhead and synchronization complexity everywhere.

Context and scope

Cooperative: async runtimes, green thread schedulers, older GUI systems. Preemptive: OS threads. Hybrids: Go preempts at function boundaries and loop backedges; Windows 3.x was purely cooperative.

Common misconceptions

  • Cooperative scheduling is only for language runtimes — kernel designs, embedded WSN stacks, and application-level task systems all use it
  • Preemption makes programs correct — preemption makes liveness robust; correctness still requires synchronization, and preemption multiplies interleavings to test
  • Yield points are cheap everywhere — missing yields in compute loops starve timers and event loops; inserting them changes performance envelopes

Anti-patterns

  • Long CPU loops without yield in single-threaded event loops, freezing heartbeats and timers
  • Assuming library callbacks always yield appropriately and shipping blocking surprises inside frameworks
  • Choosing preemptive threads for high-frequency fine-grained tasks and paying context-switch domination

Related concepts

Related examples

Authoritative source

https://en.wikipedia.org/wiki/Cooperative_multitasking

What it is

The question is who decides when a task stops running. The task itself: cooperative — switches happen at yields, cheap and always at safe points. The scheduler: preemptive — switches happen on quantums and interrupts, robust against selfish tasks but at overhead and interleaving complexity.

How it works

Cooperative runtimes insert yield points at await boundaries, channel operations, and scheduler calls; compute between yields runs untouchable. Preemptive kernels interrupt via timer, delivering full context switches through hardware support. Hybrids preempt at coarse boundaries — Go preemption at function entries and loop backedges balances latency guarantees with switch cost.

When to choose

Cooperative for massive task counts with frequent natural suspension points — I/O multiplexing pipelines. Preemptive for unknown or adversarial code and CPU-bound parallelism. Hybrid runtimes dominate modern server platforms for exactly this blend.

Pitfalls

Cooperative liveness depends on every participant — one native blocking call or tight loop stalls the world, and watchdog threads are the detection mechanism. Preemptive systems face priority inversion and cache thrash from forced migration. Diagnose cooperative stalls by measuring yield gaps, not CPU totals.