Tasks
This is what the language is for, so it has a chapter of its own. The shape of it:
import "std/mem"
func fill(mut xs []i64, v i64) { for i in 0..xs.len { xs[i] = v }}
func main() !int { mut backing := [2048]u8{} mut arena := mem.NewArena(backing[..]) mut data := mem.Alloc[i64](&arena, 64) orelse return error.OutOfMemory
scope { for part in data.chunks(8) { spawn fill(part, 2) } }
mut total i64 = 0 for i in 0..data.len { total += data[i] } return int(total % 100)}Eight tasks, each writing its own piece. The closing brace of scope waits for
all of them. Nothing here is a convention you have to remember — the compiler
rejects the versions of this program that would race.
When tasks really do need to share one structure, shared[T] puts a mutex in
front of it and lock is the only way in:
lock m := table { try m.Set(key, 1)}The brace releases it, and so does every other way out of the block.