Concurrency safety guarantees help your program avoid mistakes when many parts run at the same time. This keeps your program correct and prevents crashes or wrong results.
Concurrency safety guarantees in Rust
use std::sync::{Arc, Mutex};
let data = Arc::new(Mutex::new(0));
// Arc allows sharing ownership safely
// Mutex allows only one thread to access data at a timeArc stands for Atomic Reference Counting. It lets multiple parts share ownership safely.
Mutex is a lock that makes sure only one part can change data at once.
use std::sync::{Arc, Mutex};
use std::thread;
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!("Counter: {}", *counter.lock().unwrap());use std::sync::RwLock; let data = RwLock::new(5); { let r = data.read().unwrap(); println!("Read data: {}", *r); } { let mut w = data.write().unwrap(); *w += 1; println!("Updated data: {}", *w); }
This program creates 10 threads. Each thread safely adds 1 to the shared counter using Mutex and Arc. The final value shows the total increments.
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!("Final counter value: {}", *counter.lock().unwrap());
}Rust's ownership and type system help catch concurrency mistakes at compile time.
Mutex can cause your program to wait if another part is using the data, so use it carefully.
Arc is needed to share data safely between threads because normal references can't be shared safely.
Concurrency safety guarantees prevent bugs when multiple parts run at the same time.
Use Arc to share ownership and Mutex or RwLock to control access to shared data.
Rust helps you write safe concurrent code by checking rules before running your program.
Practice
Solution
Step 1: Understand ownership sharing in concurrency
In Rust,Arc(Atomic Reference Counted) allows multiple threads to share ownership safely.Step 2: Compare other options
Boxis for single ownership,Rcis not thread-safe, andRefCellis for interior mutability but not thread-safe.Final Answer:
Arc -> Option CQuick Check:
Safe shared ownership across threads = Arc [OK]
- Confusing Rc with Arc for multithreading
- Using Box for shared ownership
- Thinking RefCell is thread-safe
Solution
Step 1: Recall Mutex creation syntax
In Rust, you create a Mutex by callingMutex::new(value).Step 2: Check each option
Onlylet m = Mutex::new(5);uses the correctMutex::new(5)syntax; others are invalid.Final Answer:
let m = Mutex::new(5); -> Option AQuick Check:
Mutex creation uses Mutex::new() [OK]
- Omitting ::new when creating Mutex
- Using constructor syntax like Mutex(5)
- Confusing new() with create()
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());
}Solution
Step 1: Understand the code's concurrency logic
The code creates 3 threads, each increments the shared counter by 1 inside a Mutex lock.Step 2: Calculate the final counter value
Each thread adds 1, so total increments = 3. The final print shows 3.Final Answer:
3 -> Option BQuick Check:
3 threads incrementing counter = 3 [OK]
- Ignoring Mutex lock and thinking of race conditions
- Assuming only one thread runs
- Expecting compilation error due to Arc usage
use std::sync::Arc;
use std::thread;
fn main() {
let numbers = vec![1, 2, 3];
let shared_numbers = Arc::new(numbers);
let handle = thread::spawn(move || {
shared_numbers.push(4);
});
handle.join().unwrap();
}Solution
Step 1: Examine the thread code
The thread attempts to mutate the sharedArc<Vec<i32>>by callingpush, but Arc provides only shared immutable access.Step 2: Recall requirements for mutable shared data
To mutate data shared across threads, wrap it inMutexorRwLockinside the Arc, e.g.,Arc<Mutex<Vec<i32>>>.Step 3: Eliminate other options
A: Vec can be moved into Arc. B:Arc<Vec<T>>implements Send/Sync forT: Sync. D: Clone not needed for single-thread move.Final Answer:
Vector is not thread-safe without Mutex or RwLock -> Option AQuick Check:
Mutable shared data needs Mutex or RwLock [OK]
- Thinking Arc alone makes data mutable and safe
- Confusing Send trait errors
- Assuming clone is needed before move
Solution
Step 1: Identify thread-safe shared ownership
To share data across threads,Arcis needed for atomic reference counting.Step 2: Choose synchronization primitive for mutation
For mutable access,MutexorRwLockcan be used.RwLockallows multiple readers or one writer, improving concurrency.Step 3: Evaluate options
Arc<RefCell<HashMap<String, i32>>>usesRefCellwhich is notSyncand thus not thread-safe.Arc<RwLock<HashMap<String, i32>>>usesRwLockwhich is suitable for read-heavy workloads with mutations.Rc<RefCell<HashMap<String, i32>>>usesRcandRefCell, which are not thread-safe.Mutex<HashMap<String, i32>>lacksArc, so no shared ownership across threads.Final Answer:
Arc<RwLock<HashMap<String, i32>>> -> Option DQuick Check:
Arc + RwLock = safe shared mutable access [OK]
- Using Rc or RefCell for multithreading
- Omitting Arc for shared ownership
- Choosing Mutex over RwLock without reason
Ready to prove it?
Pass the test and this pattern moves unknown
