← Concepts

阅读中文版本

Cooperative Multitasking

Cooperative multitasking yields control at explicit points rather than being preempted, so a task that never yields freezes the system — simpler than preemptive but unsafe with untrusted code.

concurrency

Definition

Cooperative multitasking is a scheduling model where each task runs until it explicitly yields, so the scheduler never preempts; this is simpler and has lower context-switch overhead than preemptive scheduling, but a single task that fails to yield blocks every other task indefinitely.

Context and scope

Applied in early operating systems, event loops, generators, and any runtime where tasks are trusted to yield and preemption overhead is undesirable.

Common misconceptions

  • Cooperative multitasking is just async/await — async/await is one implementation; cooperative multitasking also includes generators, fibers, and manual yield
  • Cooperative scheduling prevents starvation — it prevents scheduler-induced starvation; a task that never yields starves everyone, which is the model weakness

Anti-patterns

  • Running untrusted code in a cooperative scheduler, so a malicious or buggy task holds the single thread forever
  • Forgetting to yield in a long computation, freezing the UI thread in a cooperative event loop

Related concepts

Authoritative source

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

What it is

Cooperative multitasking is a scheduling model where each task runs until it explicitly yields, so the scheduler never preempts; this is simpler and has lower context-switch overhead than preemptive scheduling, but a single task that fails to yield blocks every other task indefinitely. Applied in early operating systems, event loops, generators, and any runtime where tasks are trusted to yield and preemption overhead is undesirable. The central difficulty is that interleaving is nondeterministic: the set of possible executions grows super-exponentially with the number of operations, and testing samples a vanishing fraction.

How it works

Correctness is established by reasoning about happens-before relationships, not by running more tests. Synchronization primitives are chosen for the specific guarantee needed — mutual exclusion, publication, or ordering — and composed only with a documented proof of absence of deadlock. Bounded resources apply backpressure rather than unbounded queuing that hides overload until memory exhausts.

When to apply and pitfalls

Apply whenever multiple flows share mutable state or resources. The dominant pitfall is reasoning sequentially about concurrent code — “this can’t happen because A finishes before B” — when in fact the scheduler can interleave at any instruction boundary. The second is using a coarse lock for simplicity and turning parallelism back into serialization.