liveBook · Manning

Thread

As explained in Rust in Action: Systems programming concepts and techniques

A thread of execution is a sequence of CPU instructions intended to execute serially within a running program.

A thread is a sequence of CPU instructions intended to run in order within a process. Operating systems schedule threads to give each access to the CPU. A process can contain multiple threads, allowing different pieces of work to make progress without waiting for one long sequence to finish. section 10.2 section 10.5.3

Concurrency does not require multiple CPU cores. When a thread waits for memory or I/O, it can be blocked and scheduled again when its data is available. Parallelism is different: it uses multiple physical cores at the same time. Threads within one process share a memory address space, unlike separate processes. section 10.0 section 10.5

Spawn two workers

In Rust, `thread::spawn(move || { ... })` starts work in a new thread. A small timing program spawns two threads that each sleep for 300 ms, then calls `join().unwrap()` on both handles before measuring the elapsed time. The handles make the waiting explicit: spawning starts the work; joining waits for it to finish. section 10.2.3

Listing 10.3 Creating two subthreads to perform work on our behalf
 1 use std::{thread, time};
 2  
 3 fn main() {
 4   let start = time::Instant::now();
 5  
 6   let handler_1 = thread::spawn(move || {
 7     let pause = time::Duration::from_millis(300);
 8       thread::sleep(pause.clone());
 9   });
10  
11   let handler_2 = thread::spawn(move || {
12     let pause = time::Duration::from_millis(300);
13       thread::sleep(pause.clone());
14   });
15  
16   handler_1.join().unwrap();
17   handler_2.join().unwrap();
18  
19   let finish = time::Instant::now();
20  
21   println!("{:?}", finish.duration_since(start));
22 }

Follow the two `thread::spawn` calls, then the two `join` calls, to see where concurrent work begins and where the main thread waits. section 10.2.3

A few threads need not be expensive: the two-worker timing comparison found little creation overhead. Large numbers are a different matter. Each thread needs memory; scheduling and switching consume CPU time, and switching invalidates caches. CPU-heavy work can slow sharply once runnable threads outnumber physical cores. Choose a thread count for the workload rather than assuming that more threads mean more speed. section 10.2.3 section 10.2.4

Shared memory also requires care. If two spawned closures try to write the same variable, their order is not predictable because the OS schedules them. Rust rejects the illustrated attempt to give both threads and `main` access to that mutable data. Smaller concurrency mechanisms, such as coroutines, differ in another way: the OS schedules threads, while a process manages switching among its own smaller tasks. section 1.6.1 section 10.5.1

How Rust in Action: Systems programming concepts and techniques covers it

How deep it goes
Explains spawning, joining, scheduling, shared memory, and scaling costs, but stops short of implementing concurrency libraries.
Examples
Uses a timed two-thread sleep program, many-thread timing comparisons, and a rejected shared-write race.
What it assumes
Introduces threads for readers new to the term and supplies closure syntax needed for spawning them.
What you can do after
Apply it via Rust’s `std::thread` to spawn and join workers while judging thread-count costs.
How it connects
Relates threads to processes, coroutines, concurrency, parallelism, operating-system scheduling, and data races.

Also explained in

Compare how 11 books explain thread →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Rust in Action: Systems programming concepts and techniques. The section links point to the parts of the book it draws on.