Module std::threadStable [-]  [+] [src]

Native threads

The threading model

An executing Rust program consists of a collection of native OS threads, each with their own stack and local state.

Communication between threads can be done through channels, Rust's message-passing types, along with other forms of thread synchronization and shared-memory data structures. In particular, types that are guaranteed to be threadsafe are easily shared between threads using the atomically-reference-counted container, Arc.

Fatal logic errors in Rust cause thread panic, during which a thread will unwind the stack, running destructors and freeing owned resources. Thread panic is unrecoverable from within the panicking thread (i.e. there is no 'try/catch' in Rust), but panic may optionally be detected from a different thread. If the main thread panics the application will exit with a non-zero exit code.

When the main thread of a Rust program terminates, the entire program shuts down, even if other threads are still running. However, this module provides convenient facilities for automatically waiting for the termination of a child thread (i.e., join), described below.

The Thread type

Already-running threads are represented via the Thread type, which you can get in one of two ways:

Threads can be named, and provide some built-in support for low-level synchronization described below.

The Thread::current() function is available even for threads not spawned by the APIs of this module.

Spawning a thread

A new thread can be spawned using the Thread::spawn function:

fn main() { use std::thread::Thread; let thread = Thread::spawn(move || { println!("Hello, World!"); // some computation here }); }
use std::thread::Thread;

let thread = Thread::spawn(move || {
    println!("Hello, World!");
    // some computation here
});

The spawned thread is "detached" from the current thread, meaning that it can outlive the thread that spawned it. (Note, however, that when the main thread terminates all detached threads are terminated as well.) The returned Thread handle can be used for low-level synchronization as described below.

Scoped threads

Often a parent thread uses a child thread to perform some particular task, and at some point must wait for the child to complete before continuing. For this scenario, use the scoped constructor:

fn main() { use std::thread::Thread; let guard = Thread::scoped(move || { println!("Hello, World!"); // some computation here }); // do some other work in the meantime let result = guard.join(); }
use std::thread::Thread;

let guard = Thread::scoped(move || {
    println!("Hello, World!");
    // some computation here
});
// do some other work in the meantime
let result = guard.join();

The scoped function doesn't return a Thread directly; instead, it returns a join guard from which a Thread can be extracted. The join guard is an RAII-style guard that will automatically join the child thread (block until it terminates) when it is dropped. You can join the child thread in advance by calling the join method on the guard, which will also return the result produced by the thread. A handle to the thread itself is available via the thread method on the join guard.

(Note: eventually, the scoped constructor will allow the parent and child threads to data that lives on the parent thread's stack, but some language changes are needed before this is possible.)

Configuring threads

A new thread can be configured before it is spawned via the Builder type, which currently allows you to set the name, stack size, and writers for println! and panic! for the child thread:

fn main() { use std::thread; thread::Builder::new().name("child1".to_string()).spawn(move || { println!("Hello, world!") }); }
use std::thread;

thread::Builder::new().name("child1".to_string()).spawn(move || {
    println!("Hello, world!")
});

Blocking support: park and unpark

Every thread is equipped with some basic low-level blocking support, via the park and unpark functions.

Conceptually, each Thread handle has an associated token, which is initially not present:

In other words, each Thread acts a bit like a semaphore with initial count 0, except that the semaphore is saturating (the count cannot go above 1), and can return spuriously.

The API is typically used by acquiring a handle to the current thread, placing that handle in a shared data structure so that other threads can find it, and then parking. When some desired condition is met, another thread calls unpark on the handle.

The motivation for this design is twofold:

Structs

Builder

Thread configuration. Provides detailed control over the properties and behavior of new threads.

JoinGuard

An RAII-style guard that will block until thread termination when dropped.

Thread

A handle to a thread.

Type Definitions

Result

Indicates the manner in which a thread exited.