Concurrency
Concurrency in Zig runs through one interface. Anything that can block takes an `std.Io`, so the function starting the work never decides how it is scheduled, and `main` is the only place that picks. These chapters follow that from the first `io.async` call to the point where you choose an implementation: futures and groups, stopping a task that is already running, waiting for whichever finishes first, a bounded queue between two tasks, the locks under shared state, the atomics those locks are built from, and the real OS threads you drop to when the interface is not what you want, and it ends on a whole program rather than a primitive. Five of the ten run in your browser, on a target with no threads at all, which is the interface demonstrating its own point. The Io Interface chapter, in the Standard Library section, is the one to read first.
std.Thread.spawnstill exists, but it is no longer the default. Structured concurrency goes throughstd.Ioand compiles for targets that have no threads.io.asyncis allowed to run your function inline and hand back aFuturethat has already finished. Onlyio.concurrentpromises the caller keeps going, and it may fail witherror.ConcurrencyUnavailable.- Cancellation is a request, not a kill. The task finds out at its next cancellation point, which is the reason anything that can block takes the
Io. - The implementation is chosen in
mainand nowhere else. Every function below it takes the interface and never learns whether it got threads. - A mutex is not a primitive.
std.atomic.Mutexis one compare-and-swap to take the lock and one ordered store to drop it, and that is the whole type. std.Thread.Mutex,RwLock,Semaphore,Condition,ResetEvent,WaitGroupandPoolno longer exist. Everything that waits moved tostd.Io;std.Threadkeptspawnand the four calls that are really about an OS thread.- A concurrent program whose output depends on the order its tasks ran is one nobody can test. Design the result to be scheduling-independent and the concurrency becomes something you can change your mind about.
10 chapters.
- Async, Future and Groupasync, Future, and Group, all through the Io interface.
- CancellationStopping a running task, and the cancellation points that make it possible.
- SelectWaiting for whichever task finishes first, and cancelling the rest.
- QueuesIo.Queue as a bounded channel between tasks, with close and back pressure.
- Locks and SemaphoresRwLock, Semaphore and Condition, past the point where a Mutex is enough.
- AtomicsOne counter, every way to add one to it, and what that ordering argument is for.
- ThreadsReal OS threads, and why this page cannot run in your browser.
- Coming from `std.Thread`Seven names that were removed, where each one went, and why lock can now fail.
- Choosing an IoThreaded, the evented implementations, and building one yourself.
- A Batch Job RunnerFour workers, one batch, three kinds of shared state, and a measurement that says one thread did all of it.