Docs/Advanced

Atomics

Atomic integer operations.

On this page

An atomic operation changes a number in one step that other threads cannot interrupt. Use it for counters and flags shared between threads; use a Lock when several values must change together (see Sharing data between threads).

Update a number#

atomic(target op value) applies the operation to target and returns the value it had before:

Valk
fn main() {
    let count = 5
    let before = atomic(count + 2)
    println(before) // 5
    println(count)  // 7

    atomic(count - 1)
    atomic(count | 8)
    println(count)  // 14
}

The operators are +, -, &, | and ^. The target must be assignable: a variable, a global or a property. Integers and floats both work.

Load and store#

atomic_load(x) reads a value and atomic_store(x, value) writes it, each as one atomic step:

Valk
fn main() {
    let ready = 0
    atomic_store(ready, 1)
    println(atomic_load(ready)) // 1
}

Count across threads#

A shared global is visible to every thread, and atomic keeps concurrent updates from getting lost:

Valk
use valk.thread

shared hits: int (0)

fn main() {
    let workers = Array[thread.Thread[void]]{}
    each 0 .. 4 {
        workers.append(thread.start(fn() {
            each 0 .. 1000 : atomic(hits + 1)
        }) !!)
    }
    each workers as worker : worker.await()
    println(hits) // 4000
}

Properties of atomic data#

Number properties of an atomic object can be updated the same way from any thread:

Valk
use valk.thread

class Stats {
    requests: uint
}

fn main() {
    let stats: atomic Stats = Stats {}
    let worker = thread.start(fn() {
        each 0 .. 100 : atomic(stats.requests + 1)
    }) !!
    worker.await()
    println(stats.requests) // 100
}