codingstuff.io
ExploreTutorialsProblemsCS Subjects
Get Started
ExploreTutorialsProblemsCS Subjects
Get Started
codingstuff.io

Master the art of building software through interactive tutorials, real-world problems, and guided projects.

Pune, Maharashtra, India

codingstuffmail@gmail.com

Product

  • Explore
  • Tutorials
  • Problems
  • CS Subjects

Company

  • About
  • Contact
  • Privacy Policy
  • Terms & Conditions
  • Sitemap

© 2026 codingstuff.io. All rights reserved.

Built with ❤️ for developers everywhere

/
/
All Tutorials
🦀

Rust

24 / 58 topics
23Concurrency24Threads25Channels
Tutorials/Rust/Threads
🦀Rust

Threads

Updated 2026-05-15
10 min read

Threads

Concurrency is a fundamental aspect of modern programming, allowing programs to perform multiple tasks simultaneously. In Rust, concurrency is managed through threads, which enable you to run code in parallel and take full advantage of multi-core processors.

Introduction

Threads are the smallest unit of execution that can be scheduled by an operating system. They allow different parts of a program to run concurrently, improving performance and responsiveness. Rust provides robust tools for creating and managing threads, ensuring safe concurrency without data races or deadlocks.

In this tutorial, we will explore how to create and manage threads in Rust using the std::thread module. We'll cover basic thread creation, joining threads, handling errors, and more advanced concepts like scoped threads.

Concept

Rust's standard library provides a simple yet powerful API for working with threads. The std::thread module includes functions to spawn new threads, join them, and handle their lifecycle.

Creating Threads

To create a thread in Rust, you can use the spawn function from the std::thread module. This function takes a closure as an argument, which represents the code that will run on the new thread.

use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        println!("Hello from a thread!");
    });

    // Wait for the thread to finish
    handle.join().unwrap();
}

In this example, we create a new thread that prints "Hello from a thread!" and then wait for it to complete using `handle.join()`. The `join` method ensures that the main thread waits for the spawned thread to finish execution before proceeding.

### Joining Threads

Joining threads is crucial when you need to ensure that all threads have completed their tasks before your program exits. This prevents any potential data corruption or incomplete work.

```rust
use std::thread;
use std::time::Duration;

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..10 {
            println!("Number {} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("Number {} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }

    handle.join().unwrap();
}

In this example, both the main thread and the spawned thread print numbers concurrently. The `join` call ensures that the main thread waits for the spawned thread to finish before exiting.

### Handling Errors

When working with threads, it's important to handle potential errors gracefully. If a thread panics, you can catch the error using the `Result` returned by `join`.

```rust
use std::thread;

fn main() {
    let result = thread::spawn(|| {
        panic!("Something went wrong!");
    }).join();

    match result {
        Ok(_) => println!("Thread completed successfully."),
        Err(e) => println!("Thread panicked: {:?}", e),
    }
}

In this example, the spawned thread panics, and the `join` method returns an error. We handle this error using a `match` statement to print an appropriate message.

### Scoped Threads

Scoped threads are a more advanced feature that allows you to create threads with limited lifetimes. They are useful when you need to ensure that threads do not outlive their parent scope.

```rust
use std::thread;

fn main() {
    let data = vec![1, 2, 3];

    thread::scope(|s| {
        s.spawn(|| {
            println!("Data from the scoped thread: {:?}", data);
        });
    });

    // The scoped thread is guaranteed to have finished by this point
}

In this example, we create a scoped thread that accesses a vector data. The scope ensures that the thread completes before the main function exits.

Examples

Let's explore some practical examples to solidify our understanding of threads in Rust.

Example 1: Basic Thread Creation

use std::thread;
use std::time::Duration;

fn main() {
    let handle = thread::spawn(|| {
        for i in 1..5 {
            println!("Number {} from the spawned thread!", i);
            thread::sleep(Duration::from_millis(1));
        }
    });

    for i in 1..5 {
        println!("Number {} from the main thread!", i);
        thread::sleep(Duration::from_millis(1));
    }

    handle.join().unwrap();
}

Example 2: Handling Thread Errors

use std::thread;

fn main() {
    let result = thread::spawn(|| {
        panic!("Something went wrong!");
    }).join();

    match result {
        Ok(_) => println!("Thread completed successfully."),
        Err(e) => println!("Thread panicked: {:?}", e),
    }
}

Example 3: Scoped Threads

use std::thread;

fn main() {
    let data = vec![1, 2, 3];

    thread::scope(|s| {
        s.spawn(|| {
            println!("Data from the scoped thread: {:?}", data);
        });
    });

    // The scoped thread is guaranteed to have finished by this point
}

What's Next?

In the next section, we will explore how to communicate between threads using channels. Channels provide a safe way to send messages between threads and are essential for building concurrent applications.

Stay tuned!


PreviousConcurrencyNext Channels

Recommended Gear

ConcurrencyChannels