Skip to content

Rust Basics - Concurrency

Rust Basics - Concurrency

Rust makes concurrent programming safe and fearless. The ownership and type systems prevent data races at compile time.

Threads

Creating threads with std::thread:

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

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

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

handle.join().unwrap(); }

Moving Data to Threads

use std::thread;

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

let handle = thread::spawn(move || { println!("Here's a vector: {:?}", v); });

handle.join().unwrap(); }

Message Passing with Channels

use std::sync::mpsc;
use std::thread;

fn main() { let (tx, rx) = mpsc::channel();

thread::spawn(move || { let val = String::from("hi"); tx.send(val).unwrap(); });

let received = rx.recv().unwrap(); println!("Got: {}", received); }

Multiple Producers

let (tx, rx) = mpsc::channel();

let tx1 = tx.clone(); thread::spawn(move || { tx1.send("from thread 1").unwrap(); });

thread::spawn(move || { tx.send("from thread 2").unwrap(); });

for received in rx { println!("Got: {}", received); }

Shared State with Mutex

use std::sync::{Arc, Mutex};
use std::thread;

fn main() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![];

for _ in 0..10 { let counter = Arc::clone(&counter); let handle = thread::spawn(move || { let mut num = counter.lock().unwrap(); *num += 1; }); handles.push(handle); }

for handle in handles { handle.join().unwrap(); }

println!("Result: {}", *counter.lock().unwrap()); }

Send and Sync Traits

Most types implement these automatically. Raw pointers are notable exceptions.

Async/Await

use std::future::Future;

async fn do_something() { println!("doing something"); }

async fn async_main() { let future = do_something(); future.await; }

fn main() { // Using tokio runtime // tokio::runtime::Runtime::new().unwrap().block_on(async_main()); }

Concurrent Async

use tokio::time::{sleep, Duration};

async fn task1() { sleep(Duration::from_secs(1)).await; println!("Task 1 done"); }

async fn task2() { sleep(Duration::from_secs(1)).await; println!("Task 2 done"); }

async fn main_async() { // Run concurrently tokio::join!(task1(), task2()); }

Choosing Your Approach

| Use Case | Recommendation | |----------|---------------| | CPU-bound work | thread::spawn | | I/O-bound work | async/await with tokio | | Message passing | mpsc::channel | | Shared mutable state | Arc> | | Read-heavy shared data | Arc> |

Rust's type system ensures thread safety without runtime overhead!