Skip to content
volt
GitHub

std::thread

Threads, and what they share: mutex<T> (a lock around a value, reached through a guard), cond (a condition variable), atomics, shared<T> (one value with an atomic count of its copies) and channel<T> (owned values passed between threads). No OS code here: the runtime starts and joins the system's threads and sleeps and wakes on a word (a futex on Linux, ulock on macOS, WaitOnAddress on Windows); locks are built on that word.

Source: std/thread.volt

Types

error std::thread::spawn_error

error spawn_error

why spawn failed

Variant
OUT_OF_MEMORYno memory for the thread's closure
REFUSEDthe system wouldn't start another thread

struct std::thread::thread

struct thread

A running thread. Deleting it joins it (waits for it to finish), so a thread never outlives its handle, and what its closure borrows (& captures) only has to outlive the handle.

Field
handle: u64 = 0
running: bool = falsefalse: nothing to join (a default thread, or one joined already)

Methods

attach fn join(this: std::thread::thread&) -> void

wait for the thread to finish (again: nothing)

attach fn delete(this: std::thread::thread&) -> void

struct std::thread::mutex

<T: type> struct mutex

A lock around a value: lock() waits for it and gives a guard, through which the value is reached; deleting the guard unlocks it. Don't move a mutex while it's locked (share it: shared<mutex<T>>, or borrow it from a thread whose handle goes first).

Field
word: i32 = 00 free, 1 locked, 2 locked and someone may be waiting
value: Twhat it guards

Methods

<T: type> attach fn lock(this: std::thread::mutex<T>&) -> std::thread::guard<T>

wait for the lock and take it: the guard reaches the value, and unlocks when it's deleted

<T: type> attach fn try_lock(this: std::thread::mutex<T>&) -> std::thread::guard<T>?

the lock if it's free now, else null

struct std::thread::guard

<T: type> struct guard

the lock on a mutex, held until the guard is deleted

Field
m: mutex<T>*

Methods

<T: type> attach fn get(this: std::thread::guard<T>&) -> T&

the locked value

<T: type> attach fn delete(this: std::thread::guard<T>&) -> void

struct std::thread::cond

struct cond

A condition variable: wait(guard) unlocks the guard's mutex and sleeps until notified, then locks it again. It can wake without a notify, so wait in a loop that checks what it's waiting for.

Field
seq: i32 = 0bumped by every notify

Methods

<T: type> attach fn wait(this: std::thread::cond&, g: std::thread::guard<T>&) -> void

unlock g's mutex, sleep until notified (or not: check again), lock it again

attach fn notify_one(this: std::thread::cond&) -> void

wake one waiting thread

attach fn notify_all(this: std::thread::cond&) -> void

wake every waiting thread

struct std::thread::atomic_i64

struct atomic_i64

an i64 that threads can change at the same time

Field
value: i64 = 0

Methods

attach fn load(this: std::thread::atomic_i64&) -> i64
attach fn store(this: std::thread::atomic_i64&, v: i64) -> void
attach fn add(this: std::thread::atomic_i64&, n: i64) -> i64

add n; the value before

attach fn sub(this: std::thread::atomic_i64&, n: i64) -> i64

subtract n; the value before

attach fn swap(this: std::thread::atomic_i64&, v: i64) -> i64

set it to v; the value before

attach fn compare_swap(this: std::thread::atomic_i64&, expected: i64, desired: i64) -> bool

set it to desired if it's expected; whether it was

struct std::thread::atomic_bool

struct atomic_bool

a bool that threads can change at the same time

Field
value: i32 = 0

Methods

attach fn load(this: std::thread::atomic_bool&) -> bool
attach fn store(this: std::thread::atomic_bool&, v: bool) -> void
attach fn swap(this: std::thread::atomic_bool&, v: bool) -> bool

set it to v; the value before

struct std::thread::shared

<T: type, Allocator: std::mem::allocator = std::mem::default_allocator> struct shared

One value with several owners, on any threads: copy makes another owner (the count goes up atomically), and the value is deleted with the last one. Reach the value with get(); to change it from several threads, share a mutex<T> or atomics.

Field
ptr: shared_box<T>*null in an empty (default) shared
allocator: Allocatorwhat frees it

Methods

<T: type, A: std::mem::allocator> attach fn get(this: std::thread::shared<T, A>&) -> T&

the shared value

<T: type, A: std::mem::allocator> attach fn count(this: std::thread::shared<T, A>&) -> i64

how many shared<T>s point at the value (on several threads, it may change right after)

<T: type, A: std::mem::allocator> attach fn copy(this: std::thread::shared<T, A>&) -> std::thread::shared<T, A>

another owner of the same value

<T: type, A: std::mem::allocator> attach fn delete(this: std::thread::shared<T, A>&) -> void

one owner fewer; the last one deletes the value and frees its memory

struct std::thread::channel

<T: type, Allocator: std::mem::allocator = std::mem::default_allocator> struct channel

Owned values passed between threads, first in first out. A copy of a channel is the same channel (give each thread its own copy); it's deleted, with whatever was never received, with the last. Its queue and shared state come from Allocator.

Field
state: shared<chan_state<T, Allocator>, Allocator>

Methods

<T: type> attach fn new(static this: std::thread::channel<T>) -> std::mem::mem_error!std::thread::channel<T>

a new, empty channel

<T: type, A: std::mem::allocator> attach fn new_in(static this: std::thread::channel<T>, allocator: A) -> std::mem::mem_error!std::thread::channel<T, A>

a new, empty channel whose memory comes from allocator

<T: type, A: std::mem::allocator> attach fn send(this: std::thread::channel<T, A>&, value: T) -> bool

send value to whoever receives; false if the channel is closed (then value is deleted)

<T: type, A: std::mem::allocator> attach fn recv(this: std::thread::channel<T, A>&) -> T?

the next value, waiting for one if there's none yet; null once the channel is closed and empty

<T: type, A: std::mem::allocator> attach fn try_recv(this: std::thread::channel<T, A>&) -> T?

the next value if one is waiting, else null

<T: type, A: std::mem::allocator> attach fn close(this: std::thread::channel<T, A>&) -> void

no more sends: receivers get what's left, then null

Functions

std::thread::spawn

<F: type, A: std::mem::allocator = std::mem::default_allocator> fn spawn(f: F, allocator: A = {}) -> spawn_error!thread

run f, a closure with no parameters, on a new thread. f is moved there: what it captures by value or with move belongs to the thread

std::thread::yield_now

fn yield_now() -> void

let another thread run

std::thread::share

<T: type, A: std::mem::allocator = std::mem::default_allocator> fn share(value: T, allocator: A = {}) -> std::mem::mem_error!shared<T, A>

value in a new shared<T>, its only owner so far