Threads

Thread IDs

std::thread::ThreadId is an opaque, process-unique identifier assigned by the Rust standard library to each thread upon creation or first inspection (thread::current().id()).

Guarantees of ThreadId vs. OS Thread IDs (pthread_t / TID)

A critical distinction between Rust's std::thread::ThreadId and operating-system thread handles (pthread_t on Unix or DWORD thread IDs on Windows) is non-reuse:

  • OS thread IDs can be recycled by the operating system kernel immediately after a thread exits.
  • Rust's ThreadId is strictly monotonic (64-bit counter) and is NEVER reused for the entire lifetime of the process, even after the thread that owned that ThreadId terminates!
Property std::thread::ThreadId OS Thread Handle / TID
Uniqueness guarantee Never reused within the lifetime of the process Recycled by OS kernel after thread termination
Trait implementations Copy, Clone, Eq, PartialEq, Hash, Debug, Send, Sync Platform-specific FFI type (std::os::unix::thread::RawPthread)
Usable as a HashMap key? Yes (HashMap<ThreadId, State>) Requires raw integer conversion and cleanup on thread exit
How to obtain thread::current().id() or join_handle.thread().id() JoinHandleExt::as_pthread_t() / OS syscall

Using ThreadId for Per-Thread Attribution and Re-Entrancy Detection

Because ThreadId implements Copy, Eq, and Hash, it is ideal for tagging log lines, attributing metrics per worker thread in a HashMap<ThreadId, Metrics>, or detecting whether the current thread already holds a custom lock (owner_tid == Some(thread::current().id())):

use std::collections::HashMap;
use std::sync::Mutex;
use std::thread::{self, ThreadId};

fn main() {
    let work_counts: Mutex<HashMap<ThreadId, u32>> = Mutex::new(HashMap::new());

    thread::scope(|s| {
        for _ in 0..3 {
            s.spawn(|| {
                let my_tid = thread::current().id();
                for _ in 0..5 {
                    *work_counts.lock().unwrap().entry(my_tid).or_insert(0) += 1;
                }
            });
        }
    });

    let map = work_counts.lock().unwrap();
    println!("distinct ThreadIds recorded: {}", map.len());
    for (tid, count) in &*map {
        println!("  {:?} completed {} tasks", tid, count);
    }
}
distinct ThreadIds recorded: 3
  ThreadId(2) completed 5 tasks
  ThreadId(3) completed 5 tasks
  ThreadId(4) completed 5 tasks