Rust's std::thread::spawn: Create and Manage OS Threads
std::thread::spawn creates a new OS thread to run code concurrently, returning a JoinHandle to wait for completion. Use it for background tasks or parallel computations. The footgun: dropping the handle detaches the thread, risking resource leaks.
Why it exists
To allow programs to perform multiple operations at the same time by leveraging multiple CPU cores or running long-running tasks in the background without blocking the main application flow. This is the foundation of parallelism in Rust, enabling more responsive and performant applications.
The mental model
Think of thread::spawn as hiring a temporary worker for a specific task. You give them a set of instructions (the closure) and any tools they need (the captured variables). In return, you get a JoinHandle, which is like a claim ticket. You can use this ticket later to wait for the worker to finish and collect their result. If you throw away the ticket, the worker keeps going, but you can never check on them or get their result back.
How it works
thread::spawn takes a closure and moves it to a new OS thread for execution. It immediately returns a JoinHandle<T>, where T is the return type of the closure. You can call .join() on this handle, which blocks the current thread until the spawned thread finishes. The result of .join() is a Result which contains the closure's return value on success, or an error if the spawned thread panicked. If the JoinHandle is dropped before .join() is called, the thread is "detached" and continues running in the background, but can no longer be joined, which can lead to resource leaks.
When to use it
Use std::thread for heavy, CPU-bound computations that can be parallelized, or for I/O-bound tasks that would otherwise block your main thread. It's a good, low-level tool when you need direct control over OS threads. It's also frequently used with channels (std::sync::mpsc) to send data between threads.
When not to use it
For managing a large number of concurrent, I/O-bound tasks, an async runtime like Tokio or async-std is often more efficient as it uses lightweight "tasks" instead of expensive OS threads. Also, if you need to configure the thread's name or stack size, you should use thread::Builder instead of the top-level spawn function.
One canonical example
A common pattern is to perform a calculation in a background thread. You must use the move keyword before the closure to transfer ownership of any variables from the parent scope into the new thread. This satisfies the compiler's 'static lifetime requirement, as the thread now owns its data and doesn't depend on the parent's lifetime. For example: let handle = std::thread::spawn(move || { / expensive computation / 42 });. You would then call handle.join().unwrap() to block until the computation is done and retrieve the value 42.
Interview question
What happens if a JoinHandle from std::thread::spawn is dropped before calling .join()?
- a.The program crashes due to an unhandled thread resource leak.
- b.The main thread will block indefinitely, waiting for the detached thread.
- c.The spawned thread is immediately terminated by the operating system.
- d.The spawned thread continues running, but its completion cannot be awaited.Correct
Why? this is the answer
Dropping the JoinHandle before calling .join() detaches the thread, allowing it to continue execution independently in the background, but making it impossible to wait for its completion or retrieve its result. The thread is not terminated, nor does the main thread block waiting for it.
Just read this? Test yourself on what you have been reading.
Read the original → doc.rust-lang.org
- #rust
- #concurrency
- #threads
- #ownership
Put your scrolling time to good use
Learn one idea, try a quiz and save useful cards for revision. Tezvyn makes it easy to learn and stay current in your tech field, a few minutes at a time.
The iPhone app is on the way
We are building it. Until it lands, nothing here is held back from you: every interview card, your saved cards, streaks and the job board all work in Safari, plus hundreds of free practice quizzes of thirty questions each. Sign in and it all carries over to the app the day it arrives.
Want it as an icon? Tap Share at the bottom of Safari, then Add to Home Screen. It opens full screen and the cards you have read stay available offline.
We are hiring for this. Open roles that interview on rust — each one lists the topics its interview covers.
See open roles