C+
Systems · View as Markdown

Threads and atomics

Use thread::spawn for a worker with no input and thread::spawn_with to move a value into a worker. Joining consumes the handle and returns the worker's result.

import "stdlib/thread" as thread;

fn worker() -> i32 { return 42; }

fn main() -> i32 {
    let h: thread::JoinHandle[i32] = thread::spawn::[i32](worker);
    return h.join();
}

Partition-and-join is the default shared-nothing shape. Send controls which values can move to another thread; Sync controls which values may be shared. Rc[T] is not Send; Arc[T], channels, and mutexes carry the appropriate conditional marker implementations.

Scoped lending

thread::scope() permits a worker to borrow a parent local. Scope::lend records the loan through #[keeps(this)], and dropping the scope requests cancellation and joins every worker before the borrowed value can disappear.

var counts: Counts = Counts { hits: 0 };
{
    var s: thread::Scope = thread::scope();
    let started = s.lend::[Counts](counts, tally);
}

The checker rejects a lent value dying while the scope lives, a conflicting write during the loan, and lending the same exclusive place twice.

Shared state

Use channels before shared mutation. When shared state is required, stdlib/mutex provides a refcounted mutex and stdlib/atomic provides explicit integer atomics with Relaxed, Acquire, Release, AcqRel, and SeqCst orderings. The borrow checker does not prevent lock-order deadlocks.

See Concurrency for the complete model, deadlines, cancellation, generators, and the async/thread bridges. Runnable recipes are under Threads and atomics.