Concurrency is the ability of a program to execute multiple tasks simultaneously on the same CPU core. Concurrent tasks run and complete in overlapping time without specified order, unlike parallelism, where various tasks or subtasks of the same task run at the same time on hardware with multiple processors.

Rust stands out for its performance features and support for concurrency in a safe, efficient fashion. Rust’s approach to concurrency is based on the concept of “fearless concurrency” where the language aims to make it easy to write safe concurrent code through its ownership and borrowing system that enforces strict rules at compile time to prevent data traces and ensures memory safety.

result from spawning threads with Rust

Understanding Concurrency in Rust

Rust provides several concurrency primitives for writing concurrent programs, including threads, message passing, mutexes, atomic types, and async/await for asynchronous programming.

Here’s an overview of Rust’s concurrency primitives:

Rust threads are lightweight, and the absence of runtime overhead makes them well-suited for high-performance applications. Rust’s concurrency primitives integrate seamlessly with multiple libraries and frameworks for different concurrency needs.

How to Use Spawn Threads in Rust

You’ll use thestd::threadmodule to spawn threads. Thestd::thread::spawnfunction allows you to create a new thread that will run concurrently with the main thread or any other existing threads in your program.

Here’s how you can spawn a thread with thestd::thread::spawnfunction:

Themainfunction creates a new thread with thethread::spawnfunction by passing in a closure containing the code for the execution in the thread (in this case, the closure is an anonymous function). The closure prints a message indicating that the new thread is running.

Thejoinmethod on thethread_handleallows the main thread to wait for the spawned thread to complete execution. By callingjoin, the function ensures that the main thread waits for the spawned thread to complete before proceeding.

result from passing messages through channels

you’re able to spawn multiple threads and use a loop or any otherRust control structureto create multiple closures and spawn threads for each.

The for loop spawns five threads, each assigned to a unique identifieriwith the loop variable. The closures capture the value ofiwith themovekeyword to avoidownership issues, and thethread_handlesvector stores the threads for later in thejoinloop.

After spawning all the threads, themainfunction iterates over thethread_handlesvector, callsjoinon each handle, and waits for all the threads to execute.

Passing Messages Through Channels

You can pass messages through threads with channels. Rust provides functionality for message passing in thestd::sync::mpscmodule. Here,mpscstands for “multiple producer, single consumer” and it allows communication between multiple threads by sending and receiving messages through channels.

Here’s how you implement message passing through channels of inter-thread communication in your programs:

Themainfunction creates a channel withmpsc::channel()that returns asenderand areceiver. Thesendersends messages to thereceiverthat receives the messages. Themainfunction proceeds to spawn threads and move the ownership of theSenderto the thread closure. Inside the thread closure, thesender.send()function sends a message through the channel.

Thereceiver.recv()function receives the message by halting execution until the thread has received the message. Themainfunction prints the message to the console after a successful message receipt.

Note that sending a message through the channel consumes the sender. If you need to send messages from multiple threads, you can clone the sender with thesender.clone()function.

Additionally, thempscmodule provides other methods liketry_recv(), which non-blocking tries to receive a message, anditer(), which creates an iterator over the received messages.

Message passing via channels provides a safe and convenient way to communicate between threads while avoiding data races and ensuring proper synchronization.

Rust’s Ownership and Borrowing Model Guarantees Memory Safety

Rust combines ownership, borrowing, and the borrow checker to provide a robust, safe, concurrent programming framework.

The borrow checker acts as a safety net, detecting potential issues at compile-time rather than relying on runtime checks or garbage collection.