Rust Lesson 37 – Concurrency | Dataplexa

Introduction to Concurrency in Rust

In this lesson, you will learn the fundamentals of concurrency in Rust. Concurrency allows a program to perform multiple tasks at the same time, making applications faster and more responsive.

Rust is famous for providing safe concurrency without data races, which is a major challenge in many programming languages.


What Is Concurrency?

Concurrency means executing multiple tasks independently during the same time period. These tasks may run in parallel or be interleaved by the operating system.

Concurrency is commonly used in:

  • Web servers
  • Background jobs
  • Data processing systems
  • High-performance applications

Concurrency vs Parallelism

Although often confused, concurrency and parallelism are not the same.

  • Concurrency: Managing multiple tasks at once
  • Parallelism: Running tasks simultaneously on multiple CPU cores

Rust supports both.


Why Concurrency Is Hard

Traditional concurrency introduces serious problems:

  • Data races
  • Deadlocks
  • Race conditions
  • Hard-to-debug errors

Rust solves these problems at compile time using its ownership system.


Rust’s Approach to Concurrency

Rust enforces strict rules using:

  • Ownership
  • Borrowing
  • Lifetimes

If your concurrent code compiles in Rust, it is guaranteed to be free from data races.


Threads in Rust

A thread is a unit of execution. Rust uses operating system threads through the standard library.

Threads allow programs to run tasks independently.


Creating a Thread

You can create a thread using std::thread::spawn.

use std::thread;

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

This creates a new thread that runs alongside the main thread.


Waiting for Threads to Finish

Rust provides a JoinHandle to wait for threads.

use std::thread;

fn main() {
    let handle = thread::spawn(|| {
        println!("Thread running");
    });

    handle.join().unwrap();
}

Calling join() ensures the main thread waits for completion.


Sharing Data Between Threads

Sharing data safely is one of Rust’s strengths. By default, Rust does not allow unsafe shared access.

This prevents accidental data corruption.


Move Keyword

To move ownership into a thread, Rust uses the move keyword.

use std::thread;

fn main() {
    let message = String::from("Hello");

    let handle = thread::spawn(move || {
        println!("{}", message);
    });

    handle.join().unwrap();
}

Ownership of message is transferred to the thread.


Fearless Concurrency

Rust’s concurrency model is often called fearless concurrency.

This means:

  • Errors are caught at compile time
  • No data races
  • Predictable behavior

When to Use Concurrency

Use concurrency when:

  • Tasks are independent
  • Performance needs improvement
  • Waiting operations block execution

Do not use concurrency unnecessarily — simplicity is still important.


📝 Practice Exercises


Exercise 1

Create a thread that prints a message.

Exercise 2

Use join() to wait for a thread.

Exercise 3

Move a variable into a thread using move.

Exercise 4

Explain the difference between concurrency and parallelism.


✅ Practice Answers


Answer 1

thread::spawn(|| {
    println!("Hello!");
});

Answer 2

let handle = thread::spawn(|| {});
handle.join().unwrap();

Answer 3

let data = String::from("Rust");
thread::spawn(move || println!("{}", data));

Answer 4

Concurrency manages multiple tasks, while parallelism runs tasks simultaneously.


What’s Next?

In the next lesson, you will learn about Threads in Rust, including advanced thread management and best practices.