Shared State and Synchronization
25.1 shared Variables with lock / rlock
shared objects (structs, arrays, maps) must be accessed inside lock/rlock blocks. The compiler enforces this.
Lock multiple objects at once (deadlock-free ordering): lock a, b { ... }.
struct Counter {
mut:
value int
}
fn increment(shared c Counter) {
for _ in 0 .. 1000 {
lock c { // exclusive write lock
c.value++
}
}
}
fn main() {
shared c := Counter{}
mut ths := []thread{}
for _ in 0 .. 4 {
ths << spawn increment(shared c)
}
ths.wait()
rlock c { // shared read lock
println(c.value) // 4000
}
val := rlock c { c.value } // lock as an expression
_ = val
}25.2 The sync Module
Atomics: import sync.stdatomic (add_i64, load_u64, ...) or atomic int fields: struct S { mut: n atomic int }.
import sync
mut mtx := sync.new_mutex()
mtx.lock()
// critical section
mtx.unlock()
mut rw := sync.new_rwmutex()
rw.rlock()
rw.runlock()
mut once := sync.new_once()
once.do(fn () { println('init once') })
mut sem := sync.new_semaphore_init(3)
sem.wait()
sem.post()25.3 Concurrency Best Practices
Share memory by communicating (channels). Use shared + lock for state.
Keep lock regions short. Avoid nested locks across different call paths.
Never access a shared object outside lock/rlock. Join all threads before exit.