liveBook · Manning

Thread

As explained in Latency

A thread is a schedulable sequence of instructions that represents a unit of execution within a process.

A thread is an independent sequence of instructions executed within a process. Each thread has its own stack, while threads in the same process share memory and other resources. That makes threads useful for concurrent work, but access to shared resources needs synchronization to prevent race conditions and data corruption. section 7.5.1 section 9.2.1

Concurrency does not guarantee immediate execution:

  • On one CPU core, the OS switches between threads so each can make progress without running simultaneously. section 9.2.1
  • On different cores, threads can run in parallel. section 7.5.1
  • A ready thread still waits for the OS to schedule it. For low-latency work, avoid creating too many competing threads; CPU affinity can restrict application threads to specific CPUs. section 7.5.1

A waiting request

A network request cannot be processed until the OS runs the thread that handles it. This delay can matter even when the thread has no application work ahead of the request. section 7.5.1

Figure 9.2 The OS runs multiple threads at the same time (but not simultaneously) on a single CPU core by context-switching between them. In this example, every thread is run for exactly 4 milliseconds, and then the OS switches to another thread. In real-world systems, a thread might block to wait for I/O, for example, causing the OS to switch to another thread more quickly.
Figure 9.2: The OS runs multiple threads at the same time (but not simultaneously) on a single CPU core by context switching between then.

Three threads take turns on one core in illustrative four-millisecond intervals. Real scheduling is more complex, and a thread waiting for I/O may yield sooner. section 9.2.1

fn main() {
    let mut threads = vec![];
    for i in 0..10 {
        let t = std::thread::spawn(move || {
            println!("Hello from thread {}", i);
        });
        threads.push(t);
    }
    for t in threads {
        t.join().unwrap();
    }
}

Rust’s std::thread::spawn() starts work in a closure and returns a handle; the example retains ten handles and joins each thread. section 9.2.1

How Latency covers it

How deep it goes
Defines thread-local stacks and shared resources, illustrates scheduling, and shows thread creation without detailing scheduler algorithms.
Examples
Illustrates three threads taking turns on one core and ten Rust threads created and joined.
What it assumes
Introduces processes as the runtime setting for threads, while assuming familiarity with application code.
What you can do after
Apply it via Rust std::thread::spawn() and join() while accounting for scheduling delays and shared-resource hazards.
How it connects
Links threads to processes, CPU cores, context switching, mutual exclusion, and CPU affinity.

Also explained in

Compare how 12 books explain thread →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Latency. The section links point to the parts of the book it draws on.