Shared state lets multiple parts of a program use and change the same data safely. It helps programs work together without mistakes.
When multiple threads need to read and write the same information.
When you want to keep data consistent across different parts of your program.
When you need to share settings or counters between tasks.
When you want to avoid copying data many times.
When you want to coordinate work between different workers.
Syntax
Rust
use std::sync::{Arc, Mutex};
let shared_data = Arc::new(Mutex::new(0));
Arc lets multiple owners share the same data safely across threads.
Mutex makes sure only one thread changes the data at a time.
Examples
Create shared number 5 that many parts can access safely.
Rust
use std::sync::{Arc, Mutex};
let count = Arc::new(Mutex::new(5));
Copy the shared pointer, lock the data to change it, then add 1.
Rust
let data = Arc::clone(&count);
let mut num = data.lock().unwrap();
*num += 1;
Sample Program
This program creates a shared number starting at 0. Five threads each add 1 safely. At the end, it prints the total count.
Rust
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..5 {
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!("Final count: {}", *counter.lock().unwrap());
}
OutputSuccess
Important Notes
Always lock the Mutex before accessing the data to avoid errors.
Arc helps share ownership safely between threads.
Be careful to avoid deadlocks by locking only when needed and unlocking quickly.
Summary
Shared state lets many parts use the same data safely.
Use Arc to share ownership and Mutex to control access.
This helps avoid mistakes when multiple threads work together.
Practice
(1/5)
1. What is the main purpose of using Arc in Rust when working with shared state?
easy
A. To copy data between threads
B. To allow multiple ownership of the same data safely across threads
C. To create a mutable reference to data
D. To lock data so only one thread can access it at a time
Solution
Step 1: Understand what Arc does
Arc stands for Atomic Reference Counting. It allows multiple parts of a program to own the same data safely, especially across threads.
Step 2: Differentiate from locking mechanisms
Mutex is used to lock data for safe access, but Arc is about shared ownership, not locking.
Final Answer:
To allow multiple ownership of the same data safely across threads -> Option B
Quick Check:
Arc = shared ownership [OK]
Hint: Arc shares ownership safely across threads [OK]
Common Mistakes:
Confusing Arc with Mutex
Thinking Arc locks data
Assuming Arc copies data
2. Which of the following is the correct way to create a thread-safe shared integer using Arc and Mutex in Rust?
easy
A. let data = Mutex::new(Arc::new(5));
B. let data = Mutex::new(5);
C. let data = Arc::new(5);
D. let data = Arc::new(Mutex::new(5));
Solution
Step 1: Understand the order of wrapping
To share mutable data safely, wrap the data in a Mutex first, then wrap that in an Arc for shared ownership.
Step 2: Check each option
let data = Arc::new(Mutex::new(5)); correctly wraps 5 in a Mutex, then in an Arc. let data = Mutex::new(Arc::new(5)); reverses the order, which is incorrect. Options C and D miss one of the wrappers.
Final Answer:
let data = Arc::new(Mutex::new(5)); -> Option D
Quick Check:
Arc wraps Mutex for shared mutable data [OK]
Hint: Wrap data in Mutex, then Arc for shared mutable state [OK]
Common Mistakes:
Reversing Arc and Mutex order
Missing Mutex for mutability
Using Arc without Mutex for mutable data
3. What will be the output of the following Rust code snippet?
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let counter = Arc::new(Mutex::new(0));
let mut handles = vec![];
for _ in 0..3 {
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!("{}", *counter.lock().unwrap());
}
medium
A. 3
B. 0
C. 1
D. Compilation error
Solution
Step 1: Understand the shared counter
The counter is wrapped in Arc and Mutex, allowing safe shared mutable access across threads.
Step 2: Analyze thread increments
Three threads each lock the mutex, increment the counter by 1, then unlock. After all threads join, the counter should be 3.
Final Answer:
3 -> Option A
Quick Check:
3 threads increment counter once each = 3 [OK]
Hint: Count increments by threads, sum equals output [OK]
Common Mistakes:
Forgetting to clone Arc for each thread
Ignoring Mutex lock for safe access
Assuming race conditions cause wrong output
4. Identify the error in this Rust code that tries to share a vector across threads:
use std::sync::{Arc, Mutex};
use std::thread;
fn main() {
let data = Arc::new(Mutex::new(vec![1, 2, 3]));
let data2 = data.clone();
let handle = thread::spawn(move || {
data2.lock().unwrap().push(4);
});
handle.join().unwrap();
println!("{:?}", data.lock().unwrap());
}
medium
A. No error, code runs and prints [1, 2, 3, 4]
B. Cannot clone Arc with .clone(), must use Arc::clone()
C. Mutex lock is missing unwrap()
D. Vector cannot be shared across threads
Solution
Step 1: Check Arc cloning
Using data.clone() on an Arc is valid and clones the pointer safely.
Step 2: Verify Mutex locking and thread usage
The mutex is locked with unwrap(), vector is safely mutated inside the thread, and join waits for thread completion.
Final Answer:
No error, code runs and prints [1, 2, 3, 4] -> Option A
Quick Check:
Arc clone and Mutex lock correct [OK]
Hint: Arc clone works with .clone(), Mutex lock unwrap needed [OK]
Common Mistakes:
Thinking Arc::clone() is mandatory
Forgetting to unwrap Mutex lock
Believing vectors can't be shared across threads
5. You want to safely share a counter between multiple threads and increment it only if the current value is even. Which approach correctly uses Arc and Mutex to achieve this?
hard
A. Use Arc<i32> only, clone Arc for each thread, increment directly
B. Use Mutex<Arc<i32>>, clone Mutex for each thread, increment without locking
C. Wrap the counter in Arc<Mutex<i32>>, clone Arc for each thread, lock mutex, check if even, then increment
D. Use Mutex<i32> only, share by cloning Mutex, increment without Arc
Solution
Step 1: Understand shared mutable state needs
To share and mutate data safely across threads, use Arc for shared ownership and Mutex for safe mutable access.
Step 2: Analyze each option
Wrap the counter in Arc<Mutex<i32>>, clone Arc for each thread, lock mutex, check if even, then increment correctly wraps the counter in Arc<Mutex<i32>>, clones Arc for threads, locks mutex before checking and incrementing. Other options misuse order or omit locking.
Final Answer:
Wrap the counter in Arc<Mutex<i32>>, clone Arc for each thread, lock mutex, check if even, then increment -> Option C
Quick Check:
Arc + Mutex + lock for safe conditional increment [OK]
Hint: Arc for sharing, Mutex for locking before mutate [OK]
Common Mistakes:
Not locking mutex before mutate
Using Arc without Mutex for mutability
Cloning Mutex instead of Arc
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.