Concurrency
Concurrency in Zig uses one interface. Anything that can block takes an `std.Io`, so the function that starts the work never decides how the work is scheduled. Only `main` makes that choice. These chapters follow the interface from the first `io.async` call to the point where you choose an implementation. The first topics are futures and groups, how to stop a task that already runs, how to wait for the first task that finishes, and a bounded queue between two tasks. The other topics are the locks under shared state, the atomics that make those locks, and the OS threads to use when the interface is not what you want. The section ends with a full program, not a primitive. Five of the ten chapters run in your browser, on a target with no threads, and this shows that the interface keeps its promise. Read the Io Interface chapter, in the Standard Library section, first.
std.Thread.spawnstill exists, but it is not the default now. Structured concurrency usesstd.Io, and it compiles for targets that have no threads.io.asynccan run your function inline and return aFuturethat is already complete. Onlyio.concurrentpromises that the caller continues, andio.concurrentcan fail witherror.ConcurrencyUnavailable.- Cancellation is a request, not a kill. The task gets the request at its next cancellation point. That is the reason why anything that can block takes the
Io. - Only
mainchooses the implementation. Every function belowmaintakes the interface, and never learns if the implementation has threads. - A mutex is not a primitive.
std.atomic.Mutexis one compare-and-swap that takes the lock and one ordered store that releases the lock. The type does nothing more. std.Thread.Mutex,RwLock,Semaphore,Condition,ResetEvent,WaitGroupandPooldo not exist now. Everything that waits moved tostd.Io.std.Threadkeptspawnand the four calls that are really about an OS thread.- If the output of a concurrent program depends on the order of its tasks, nobody can test the program. Make the result independent of the schedule. Then you can change the concurrency later, and the result stays the same.
10 chapters.
- Async, Future and Groupasync, Future, and Group, all through the Io interface.
- CancellationHow to stop a task that runs, and the cancellation points that make it possible.
- SelectWait for the task that completes first, and cancel the other tasks.
- QueuesIo.Queue as a bounded channel between tasks, with close and back pressure.
- Locks and SemaphoresRwLock, Semaphore and Condition, for the cases where a Mutex is not sufficient.
- AtomicsOne counter, all the ways to add one to it, and the purpose of the ordering argument.
- ThreadsReal OS threads, and why this page cannot run in your browser.
- Migrate from `std.Thread`Seven names that Zig removed, where each one went, and why lock can now fail.
- Choose an IoThreaded, the evented implementations, and how to build an Io yourself.
- A Batch Job RunnerFour workers, one batch, three kinds of shared state, and a measurement that says one thread did all of the work.