Bird
Raised Fist0
Rustprogramming~20 mins

Concurrency safety guarantees in Rust - Practice Problems & Coding Challenges

Choose your learning style10 modes available
Challenge - 5 Problems
🎖️
Concurrency Safety Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate
2:00remaining
Output of shared mutable state with Mutex
What is the output of this Rust program that uses a Mutex to safely increment a shared counter across threads?
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!("{}", *counter.lock().unwrap());
}
A5
B0
CCompilation error due to Mutex usage
DRuntime panic due to deadlock
Attempts:
2 left
💡 Hint
Think about how Mutex and Arc work together to allow safe shared mutable access.
🧠 Conceptual
intermediate
1:30remaining
Rust's Send and Sync traits purpose
Which statement best describes the purpose of Rust's Send and Sync traits in concurrency safety?
ASend allows ownership transfer between threads; Sync allows safe shared references between threads.
BSend allows multiple threads to mutate data simultaneously; Sync prevents data races by locking.
CSend and Sync traits automatically implement thread pools for concurrency.
DSend and Sync are used to serialize data for network transmission.
Attempts:
2 left
💡 Hint
Think about what it means to move or share data safely across threads.
🔧 Debug
advanced
2:00remaining
Identify the concurrency safety issue
What error will this Rust code produce when compiled or run?
Rust
use std::thread;

fn main() {
    let mut data = vec![1, 2, 3];
    let handle = thread::spawn(|| {
        data.push(4);
    });
    handle.join().unwrap();
    println!("{:?}", data);
}
ARuntime panic due to data race
BCompilation error: cannot move `data` into closure because it is borrowed
CCompilation error: closure may outlive the current function but borrows `data`
DProgram prints [1, 2, 3, 4]
Attempts:
2 left
💡 Hint
Consider how Rust handles ownership and borrowing when spawning threads.
📝 Syntax
advanced
1:30remaining
Correct syntax for atomic increment
Which option correctly increments an AtomicUsize safely in multiple threads?
Rust
use std::sync::atomic::{AtomicUsize, Ordering};

fn main() {
    let counter = AtomicUsize::new(0);
    // increment code here
    println!("{}", counter.load(Ordering::SeqCst));
}
Acounter.increment();
Bcounter += 1;
Ccounter.load(Ordering::SeqCst) += 1;
Dcounter.fetch_add(1, Ordering::SeqCst);
Attempts:
2 left
💡 Hint
Atomic types have special methods for safe mutation.
🚀 Application
expert
2:30remaining
Number of items in a concurrent HashMap after insertions
Given this Rust code using the `dashmap` crate for concurrent hashmap, how many items will be in the map after all threads finish?
Rust
use dashmap::DashMap;
use std::sync::Arc;
use std::thread;

fn main() {
    let map = Arc::new(DashMap::new());
    let mut handles = vec![];

    for i in 0..10 {
        let map = Arc::clone(&map);
        let handle = thread::spawn(move || {
            for j in 0..5 {
                map.insert(i * 5 + j, i);
            }
        });
        handles.push(handle);
    }

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

    println!("{}", map.len());
}
A10
B50
C5
DCompilation error due to DashMap usage
Attempts:
2 left
💡 Hint
Each thread inserts 5 unique keys; there are 10 threads.

Practice

(1/5)
1. Which Rust type is used to safely share ownership of data across multiple threads?
easy
A. Rc
B. Box
C. Arc
D. RefCell

Solution

  1. Step 1: Understand ownership sharing in concurrency

    In Rust, Arc (Atomic Reference Counted) allows multiple threads to share ownership safely.
  2. Step 2: Compare other options

    Box is for single ownership, Rc is not thread-safe, and RefCell is for interior mutability but not thread-safe.
  3. Final Answer:

    Arc -> Option C
  4. Quick Check:

    Safe shared ownership across threads = Arc [OK]
Hint: Arc is for thread-safe shared ownership [OK]
Common Mistakes:
  • Confusing Rc with Arc for multithreading
  • Using Box for shared ownership
  • Thinking RefCell is thread-safe
2. Which of the following is the correct syntax to create a Mutex protecting an integer value 5?
easy
A. let m = Mutex::new(5);
B. let m = Mutex(5);
C. let m = new Mutex(5);
D. let m = Mutex::create(5);

Solution

  1. Step 1: Recall Mutex creation syntax

    In Rust, you create a Mutex by calling Mutex::new(value).
  2. Step 2: Check each option

    Only let m = Mutex::new(5); uses the correct Mutex::new(5) syntax; others are invalid.
  3. Final Answer:

    let m = Mutex::new(5); -> Option A
  4. Quick Check:

    Mutex creation uses Mutex::new() [OK]
Hint: Use Mutex::new(value) to create a Mutex [OK]
Common Mistakes:
  • Omitting ::new when creating Mutex
  • Using constructor syntax like Mutex(5)
  • Confusing new() with create()
3. What will the following Rust code print?
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. 0
B. 3
C. Compilation error
D. 1

Solution

  1. Step 1: Understand the code's concurrency logic

    The code creates 3 threads, each increments the shared counter by 1 inside a Mutex lock.
  2. Step 2: Calculate the final counter value

    Each thread adds 1, so total increments = 3. The final print shows 3.
  3. Final Answer:

    3 -> Option B
  4. Quick Check:

    3 threads incrementing counter = 3 [OK]
Hint: Count threads incrementing inside Mutex lock [OK]
Common Mistakes:
  • Ignoring Mutex lock and thinking of race conditions
  • Assuming only one thread runs
  • Expecting compilation error due to Arc usage
4. Identify the error in this Rust code snippet that tries to share a vector across threads:
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();
}
medium
A. Vector is not thread-safe without Mutex or RwLock
B. Arc does not implement Send for Vec<T>
C. Cannot move vector into Arc
D. Missing clone of Arc before move

Solution

  1. Step 1: Examine the thread code

    The thread attempts to mutate the shared Arc<Vec<i32>> by calling push, but Arc provides only shared immutable access.
  2. Step 2: Recall requirements for mutable shared data

    To mutate data shared across threads, wrap it in Mutex or RwLock inside the Arc, e.g., Arc<Mutex<Vec<i32>>>.
  3. Step 3: Eliminate other options

    A: Vec can be moved into Arc. B: Arc<Vec<T>> implements Send/Sync for T: Sync. D: Clone not needed for single-thread move.
  4. Final Answer:

    Vector is not thread-safe without Mutex or RwLock -> Option A
  5. Quick Check:

    Mutable shared data needs Mutex or RwLock [OK]
Hint: Mutable shared data needs Mutex or RwLock [OK]
Common Mistakes:
  • Thinking Arc alone makes data mutable and safe
  • Confusing Send trait errors
  • Assuming clone is needed before move
5. You want to safely share and mutate a HashMap across multiple threads in Rust. Which combination of types ensures concurrency safety and allows mutation?
hard
A. Arc<RefCell<HashMap<String, i32>>>
B. Mutex<HashMap<String, i32>>
C. Rc<RefCell<HashMap<String, i32>>>
D. Arc<RwLock<HashMap<String, i32>>>

Solution

  1. Step 1: Identify thread-safe shared ownership

    To share data across threads, Arc is needed for atomic reference counting.
  2. Step 2: Choose synchronization primitive for mutation

    For mutable access, Mutex or RwLock can be used. RwLock allows multiple readers or one writer, improving concurrency.
  3. Step 3: Evaluate options

    Arc<RefCell<HashMap<String, i32>>> uses RefCell which is not Sync and thus not thread-safe. Arc<RwLock<HashMap<String, i32>>> uses RwLock which is suitable for read-heavy workloads with mutations. Rc<RefCell<HashMap<String, i32>>> uses Rc and RefCell, which are not thread-safe. Mutex<HashMap<String, i32>> lacks Arc, so no shared ownership across threads.
  4. Final Answer:

    Arc<RwLock<HashMap<String, i32>>> -> Option D
  5. Quick Check:

    Arc + RwLock = safe shared mutable access [OK]
Hint: Use Arc with RwLock for shared mutable access [OK]
Common Mistakes:
  • Using Rc or RefCell for multithreading
  • Omitting Arc for shared ownership
  • Choosing Mutex over RwLock without reason
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard