Rust ArcAsync RustChannelsConcurrencyFuturesMutexRustThreadsTokio

Article & Tutorial

Rust Concurrency: Threads, Channels, Mutex, Arc, Send and Sync

Learn Rust concurrency with threads, move closures, channels, shared state, Mutex, Arc, Send and Sync, including practical multithreaded examples.

Rust Concurrency: Threads, Channels, Mutex, Arc, Send and Sync article illustration
Rust Concurrency: Threads, Channels, Mutex, Arc, Send and Sync article illustration
Contents

Rust Learning Path — Chapter 21. Rust's ownership and type systems extend naturally into concurrent programming. Many data-race mistakes that would become runtime bugs in other languages are rejected at compile time. This chapter covers threads, message passing, shared state, Mutex, Arc, and the Send/Sync marker traits.

1. Spawn a thread

bash
use std::thread; fn main() { let handle = thread::spawn(|| { println!("worker running"); }); handle.join().unwrap(); }

join() waits for the spawned thread to finish.

2. move captured values into a thread

bash
let values = vec![1, 2, 3]; let handle = std::thread::spawn(move || { println!("{values:?}"); }); handle.join().unwrap();

The move closure takes ownership so the spawned thread cannot outlive borrowed stack data.

3. Message passing with channels

bash
use std::{sync::mpsc, thread}; fn main() { let (tx, rx) = mpsc::channel(); thread::spawn(move || { tx.send(String::from("done")).unwrap(); }); println!("{}", rx.recv().unwrap()); }

4. Multiple producers

bash
let (tx, rx) = std::sync::mpsc::channel(); let tx2 = tx.clone();

Each sender can be moved into a different worker. The receiver consumes incoming messages.

5. Shared mutable state with Mutex

bash
use std::sync::Mutex; let counter = Mutex::new(0); { let mut value = counter.lock().unwrap(); *value += 1; } println!("{:?}", counter);

A mutex allows only one holder of the protected value at a time.

6. Share ownership with Arc

bash
use std::{sync::{Arc, Mutex}, thread}; fn main() { let counter = Arc::new(Mutex::new(0)); let mut handles = vec![]; for _ in 0..4 { let counter = Arc::clone(&counter); handles.push(thread::spawn(move || { let mut value = counter.lock().unwrap(); *value += 1; })); } for handle in handles { handle.join().unwrap(); } println!("{}", *counter.lock().unwrap()); }

7. Keep lock scopes small

Holding a lock while doing slow work reduces concurrency and can contribute to deadlocks. Acquire the guard as late as possible and release it as early as possible.

8. Send and Sync

Send indicates a type can safely transfer ownership to another thread. Sync indicates shared references can be used safely across threads. Most ordinary Rust types implement these automatically when their contents permit it.

9. Why Rc is not for threads

Rc uses non-atomic reference counting and is not Send. Use Arc when ownership must be shared across threads.

10. Thread pools

Creating one OS thread for every tiny job does not scale indefinitely. Production servers typically use a pool or an asynchronous runtime. Chapter 22 moves from OS-thread primitives into Tokio's async task model.

11. Panic handling

bash
let result = thread::spawn(|| panic!("boom")).join(); if result.is_err() { eprintln!("worker failed"); }

12. Common concurrency mistakes

  • Holding mutex guards across expensive work.
  • Using shared state when message passing would be simpler.
  • Creating unbounded numbers of threads.
  • Ignoring worker panics.
  • Attempting to use Rc or RefCell across threads.

13. Mini lab: parallel counter

Create eight workers. Give each worker a vector slice or independent unit of work, send results back over a channel, and aggregate them on the main thread. Then implement a second version with Arc and compare the designs.

Key takeaways

Rust makes ownership part of concurrency design. Prefer the simplest model: isolated ownership first, messages when workers exchange data, and shared synchronization only when state truly must be shared.

Did this help?

Yes No

Join the discussion

0 Comments

Ask questions, add context, or share what worked.

Sign in to join the discussion

No comments yet. Start the discussion.

More from Melochip Editorial

Related articles

Stay in the loop. Get new Melochip articles

Receive Melochip article updates when new articles are available. Explicit opt-in only.

No pre-checked boxes. Unsubscribe support is part of the subscriber foundation.