rokdocs
v0.1

3.4. thread:: - OS threads (1:1 model)

The rok::std::thread module is the entry point for OS-level threads. As set out in 2.18 task, it is a separate abstraction from tasks, which run on the M:N cooperative scheduler; this module provides the path for spawning native threads directly.

3.4.1. When to use thread vs. task

The following table indicates which to choose in which situation.

SituationRecommendation
General concurrency / async I/Otask::spawn (lightweight)
CPU-bound computationtask::spawn or par::* (work-stealing)
Blocking C library callsthread::spawn (avoids blocking the task scheduler)
Where an OS thread API is requiredthread::spawn (TLS, signal mask, etc.)
Embedded / no-taskthread::spawn

In short, tasks come first wherever they are light and expressive enough, and dropping down to threads is for places that must deal with OS resources directly.

3.4.2. API

The basic types and function signatures are as follows.

struct Thread { /* OS handle - not generic */ }
struct JoinHandle<T> { /* join result T */ }
struct ThreadId { /* opaque */ }

struct JoinError { code: i32; }          // OS join error number (errno), JOIN_LOST or JOIN_TAKEN
const JOIN_LOST: i32 = -1;               // the thread ended with a failed REPL cell
const JOIN_TAKEN: i32 = -2;              // already joined or detached
// implements Display, Debug and Error

fn spawn<T: Send>(f: fn() -> T + Send) -> JoinHandle<T>;

struct Builder {
    name: str | none;
    stack_size: usize | none;
}

impl Builder {
    fn new() -> Builder;
    fn name(self, name: str) -> Builder;
    fn stack_size(self, size: usize) -> Builder;
    fn spawn<T: Send>(self, f: fn() -> T + Send) throws (IoError) -> JoinHandle<T>;
}

impl<T> JoinHandle<T> {
    fn join(self) throws (JoinError) -> T;
    fn detach(self);                     // does not join - the thread runs to completion
    fn thread(self) -> Thread;
}

impl Thread {
    fn id(self) -> ThreadId;
    fn name(self) -> str | none;        // name given with Builder::name (also set as the OS thread name), none if absent
    fn unpark(self);
}

// current thread
fn current() -> Thread;
fn yield_now();
fn sleep(dur: Duration);
fn park();                                     // blocks until unparked (may return without a reason)
fn park_timeout(dur: Duration);

// thread-local storage
fn local<T>(init: fn() -> T + Sync) -> ThreadLocal<T>;     // init is called on first use in each thread

impl<T> ThreadLocal<T> {
    fn get(self) -> T;                       // value of the current thread
    fn set(self, value: T);
    fn with<R>(self, f: fn(T) -> R) -> R;
}

Thread::unpark sets that thread's park token and wakes it. A token is consumed by one park.

Panics and JoinError

A panic in any thread terminates the whole process with exit code 101. join therefore never receives another thread's panic, and JoinError represents OS-level join failures, or JOIN_LOST for a thread that ended with a failed REPL cell (refs-lang 9.7.0), displayed as "thread join failed: the thread ended with a failed REPL cell".

JOIN_TAKEN (-2): the handle, or a copy of it, was already joined or detached. A second join throws it; a second detach does nothing.

3.4.3. Examples

From the simplest spawn-join pattern to builders and multiple spawns:

use rok::std::thread;

let h = thread::spawn(|| {
    heavy_blocking_work()
});
let result = try h.join();

// builder
let h = try thread::Builder::new()
    .name("worker-1")
    .stack_size(4 * 1024 * 1024)
    .spawn(|| { ... });

// multiple
let handles: List<JoinHandle<i64>> = (0..10)
    .map(|i| thread::spawn(|| { compute(i) }))
    .collect();

let results: List<i64> = handles
    .into_iter()
    .map(|h| try! h.join())
    .collect();

3.4.4. Thread-local storage

When each thread needs its own independent storage, use thread::local.

let counter = thread::local(|| 0);

try thread::spawn(|| {
    counter.set(counter.get() + 1);         // only this thread's value changes
}).join();

3.4.5. impl / target

Per-platform support:

Itemlinux/macos/windowswasm32-wasi / browserwasm32-wasi-threads
spawn✓throws Unsupported✓
Builder✓throws Unsupported✓
local✓✓ (one thread)✓
park/unparkfutex / WaitOnAddress✓✓

On wasm32-wasi and in the browser there is one thread: thread::current().name() is none. On wasm32-wasi-threads, rok_cpu_count() and the available parallelism are 4, since WASI cannot report a core count.

Edit this page on GitHub