DEV Community

Cover image for Day 28: Threads, Channels, and Rusty Messages: Unveiling the Multithreading Symphony πŸš€
Aniket Botre
Aniket Botre

Posted on

Day 28: Threads, Channels, and Rusty Messages: Unveiling the Multithreading Symphony πŸš€

Just like a chef in a restaurant kitchen simultaneously juggling multiple tasks, threads in Rust allow us to do multiple things at once. Rust threads are summoned into existence using the std::thread module. The JoinHandle type in Rust is like the magic wand that keeps track of these threads and allows you to wait for them to finish their tasks. In this deep dive, we will explore the threads, channels, and the intriguing art of message passing in the Rust programming language.

I would also recommend to check the resource on multithreading on Rust by Book website. They have explained this concept in a detailed manner.


thread in Rust 🧡

Threads in Rust are the backbone of concurrent programming. Created using the std::thread module, they are your digital minions. The JoinHandle type in Rust is like the magic wand that keeps track of these threads and allows you to wait for them to finish their tasks.Β 

Here's a simple example of how a new thread is spawned in Rust:

use std::thread;

fn main() {
    let new_thread = thread::spawn(|| {
        println!("This is a new thread. 🌐");
    });

    new_thread.join().unwrap(); // Ensure the main thread waits
}
Enter fullscreen mode Exit fullscreen mode

In this code snippet, thread::spawn takes a closure that contains the code to be executed in the new thread. The join method, just like a patient parent, ensures that the main thread waits for the new thread to complete its execution before going ahead.


🏁Thread Safety and Ownership: A Secure Partnership

Rust is like a strict parent when it comes to thread safety. It uses its ownership rules to enforce thread safety. Transferring ownership between threads prevents data races. When you try to use data across threads, Rust makes sure at compile time that you're following all the rules for safe concurrency. In other words, Rust has your back! πŸ›‘οΈ

Let's consider this example:

use std::thread;

fn main() {
    let value = 10;
    let handle = thread::spawn(move || {
        println!("The value is: {}", value);
    });

    handle.join().unwrap();
}
Enter fullscreen mode Exit fullscreen mode

In this code, the move keyword is used to move the value into the closure's environment, transferring ownership to the new thread. This is like the thread signing a contract that it is now the rightful owner of value. Without move, Rust's borrow checker would raise a red flag if there was a risk of a data race.


πŸ’ŒMessage Passing in Rust: The Thread Whisperer

Message passing is a method of inter-thread communication where threads communicate by sending each other messages rather than sharing memory. It’s like passing secret notes in class, but the teacher is totally okay with it.

Rust's standard library provides channels which are FIFO(First In First Out) queues where one thread can send messages to another.

Here's an example of creating a channel and using it to send data from one thread to another:

use std::sync::mpsc; // multiple producer, single consumer
use std::thread;

fn main() {
    // Create a new channel
    let (tx, rx) = mpsc::channel();

    // Spawn a new thread and move the sender into it
    thread::spawn(move || {
        let message = "Hello from the thread";
        tx.send(message).unwrap();
    });

    // Receive the message in the main thread
    let received = rx.recv().unwrap();
    println!("Received: {}", received);
}
Enter fullscreen mode Exit fullscreen mode

In this example, mpsc::channel creates a new channel which returns a Tuple, the first element of which is the sending endβ€Š-β€Šthe transmitterβ€Š-β€Šand the second element is the receiving endβ€Š-β€Šthe receiver. The send method is used to send data to the channel, and recv is used to receive data from the channel.

The abbreviations tx and rx are traditionally used in many fields for transmitter and receiver respectively, so we name our variables as such to indicate each end.

mpsc stands for multiple producer, single consumer.


🎁Wrapping Up

Multithreading in Rust is a powerful feature that helps us write concurrent applications that are safe from data races and other concurrency issues. By using threads, channels, and message passing, Rust programs can perform complex tasks concurrently, making efficient use of system resources. Rust's strict compile-time checks ensure that multithreaded code adheres to safety guarantees, preventing common concurrency pitfalls.

In this blog, we've taken a deep dive into the pool of threads, channels, and message passing in Rust. We've unraveled the mysteries around these concepts and hopefully, left you with a clear understanding.

But before we conclude, we would like to remind you that our journey into Rust's concurrency features has just begun. Tomorrow, we will sail into the sea of concurrent programming in Rust. So, stay tuned and keep those code editors ready! πŸŽ‰

RustLang #Multithreading #Programming #ConcurrencyJourney

Top comments (1)

Collapse
 
rdarrylr profile image
Darryl Ruggles

Lots of great posts about Rust - thanks!