Sharing with Arc and Mutex
Safely mutate shared state.
Sharing with Arc and Mutex is a free Learn Rust Coding lesson on CoddyKit — lesson 3 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Learn Rust Coding learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
The Need for Shared State
Sometimes several threads must read or update the same data. Moving ownership to a single thread is not enough.
Rust gives you safe shared ownership across threads with Arc, and safe mutation with Mutex. Together they enable shared, mutable state.
Arc: Atomic Reference Counting
Arc stands for atomically reference counted. It is like Rc, but its counter uses atomic operations, so it is safe across threads.
Cloning an Arc does not copy the data. It only increments the count and returns another handle to the same value.
use std::sync::Arc;
fn main() {
let shared = Arc::new(vec![1, 2, 3]);
let clone = Arc::clone(&shared);
println!("{:?} {:?}", shared, clone);
}Sharing Arc Across Threads
To share read-only data, clone the Arc once per thread and move each clone in. All threads point to the same allocation.
Because Arc is Send and Sync, this compiles cleanly.
use std::sync::Arc;
use std::thread;
fn main() {
let data = Arc::new(vec![10, 20, 30]);
let mut handles = vec![];
for i in 0..3 {
let d = Arc::clone(&data);
handles.push(thread::spawn(move || println!("{}", d[i])));
}
for h in handles { h.join().unwrap(); }
}Arc Alone Is Read-Only
Arc gives you shared ownership, but only shared, immutable access to the inner value.
You cannot mutate data through an Arc directly, because multiple threads holding it at once would race. You need interior mutability with a lock.
Mutex: Mutual Exclusion
A Mutex guards data so only one thread can access it at a time. You call lock to get access.
lock returns a Result; unwrapping gives a smart pointer guard. Other threads block until the guard is dropped.
use std::sync::Mutex;
fn main() {
let m = Mutex::new(0);
{
let mut guard = m.lock().unwrap();
*guard += 5;
}
println!("{:?}", m);
}The Guard and RAII
The value returned by lock is a MutexGuard. You access the inner data by dereferencing it with *.
When the guard goes out of scope, the lock is released automatically. This RAII style prevents forgetting to unlock.
Combining Arc and Mutex
To share mutable state across threads, wrap a Mutex inside an Arc. The Arc shares ownership; the Mutex guards mutation.
This pattern, Arc<Mutex<T>>, is the standard way to do shared mutable state in Rust.
use std::sync::{Arc, Mutex};
fn main() {
let counter = Arc::new(Mutex::new(0));
let c = Arc::clone(&counter);
*c.lock().unwrap() += 1;
println!("{}", *counter.lock().unwrap());
}A Shared Counter
Here ten threads each increment a shared counter. Each clones the Arc, locks the Mutex, and adds one.
Because the lock serializes access, the final total is always exactly ten.
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 c = Arc::clone(&counter);
handles.push(thread::spawn(move || {
*c.lock().unwrap() += 1;
}));
}
for h in handles { h.join().unwrap(); }
println!("{}", *counter.lock().unwrap());
}Keep Critical Sections Short
The code while a lock is held is the critical section. Other threads wait there, so keep it short.
Lock, do the minimal update, then release. Avoid heavy computation or I/O while holding the lock.
use std::sync::Mutex;
fn main() {
let m = Mutex::new(Vec::new());
{
let mut v = m.lock().unwrap();
v.push(1);
} // lock released here
println!("{:?}", m.lock().unwrap());
}Deadlocks and Poisoning
If a thread locks the same Mutex twice, or two threads lock two mutexes in opposite orders, you can deadlock and hang forever.
If a thread panics while holding a lock, the Mutex becomes poisoned, and later lock calls return an Err.
RwLock for Many Readers
When reads vastly outnumber writes, RwLock can be better than Mutex. It allows many concurrent readers or one exclusive writer.
Use read for shared access and write for exclusive access.
use std::sync::RwLock;
fn main() {
let lock = RwLock::new(5);
{
let r = lock.read().unwrap();
println!("read {}", *r);
}
*lock.write().unwrap() += 1;
println!("{}", *lock.read().unwrap());
}Quick Check
Test your understanding of Arc and Mutex.
Recap
You learned that Arc shares ownership across threads with atomic reference counting, but only allows immutable access.
A Mutex guards mutation, handing out a guard that releases on drop. Combine them as Arc<Mutex<T>> for shared mutable state, watching for deadlocks and poisoning.
Next you will join threads and collect their results.
Frequently asked questions
Is the “Sharing with Arc and Mutex” lesson free?
Yes — the full text of “Sharing with Arc and Mutex” is free to read here on the web, and the Learn Rust Coding course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Learn Rust Coding course, upgrade to CoddyKit PRO.
What will I learn in “Sharing with Arc and Mutex”?
Safely mutate shared state. You practise Learn Rust Coding with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Learn Rust Coding?
No prior experience is required. Learn Rust Coding on CoddyKit is structured for beginners through advanced learners; this is — lesson 3 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Sharing with Arc and Mutex” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Learn Rust Coding lesson?
Yes. Every Learn Rust Coding lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- Spawning Threads
- Moving Data into Threads
- Sharing with Arc and Mutex
- Joining and Collecting Results