atomic - reads and writes no other routine can see half of.
A mutex makes a whole section of code the property of one routine. These make a single read, write or addition indivisible, which is less and is often all that is wanted: a counter every routine bumps, a flag one routine raises and the others watch. That costs one instruction here against a pipe, a wait and a wake with sync.Mutex.
The rest of sync is written in tau because a pipe is enough to build it. This is not: the processor's instructions are the primitive, and no arrangement of pipes is one. So this module is the one place in sync with a shared object of its own - it cannot borrow the C library the way math does, since these are instructions the compiler emits inline and not functions with a name to look up.
Where a mutex would still be needed: anything touching two values at once. Atomics make each of them safe on its own and say nothing about the pair.
¶Int = fn(v)source
Int is an integer several routines may read and write at once.
hits = atomic.Int(0)
... in every routine:
hits.Add(1)
... after they are done:
hits.Load()The cell is eight bytes the collector owns, so an Int costs nothing to get rid of: it goes when nothing holds it, like any other value.
¶Load = fn()source
Load returns what the cell holds.
¶Store = fn(n)source
Store writes n into the cell.
¶Add = fn(delta)source
Add adds delta and returns what the cell holds afterwards. That answer belongs to the caller alone: no two routines adding at once are given the same one, which is what makes it usable as a ticket.
¶Swap = fn(n)source
Swap writes n and returns what was there before.
¶CompareAndSwap = fn(old, new)source
CompareAndSwap writes new if the cell holds old, and reports whether it did. It is what a change that has to read the old value first is built from: read, work out the new one, and try until this one takes.
¶Bool = fn(v)source
Bool is a flag several routines may read and write at once, an Int holding 0 or 1.
stop = atomic.Bool(false)
... one routine:
stop.Store(true)
... the others:
if stop.Load() { return }
¶Load = fn()source
Load returns what the flag holds.
¶Store = fn(x)source
Store writes x into the flag.
¶Swap = fn(x)source
Swap writes x and returns what was there before.
¶CompareAndSwap = fn(old, new)source
CompareAndSwap writes new if the flag holds old, and reports whether it did.