Knowledge Test Score Board
— · 0%
Work through the questions below — your score updates as you go.
Keep going · grade bands mapped to DCU's honours scale
Only your first attempt at each question counts toward this score. Reload the page to reset.
This section contains 20 interactive knowledge checks designed to test your understanding of the materials covered in Chapter 10. The questions cover OS threads, message passing via channels, shared state using Mutex and Arc, atomic operations, and the marker traits that guarantee thread safety.
Please remember that many of the quizzes have multiple correct answers , and you must select all applicable options to succeed. I have carefully balanced the lengths of the answers, so take your time to evaluate each option thoroughly.
Good luck!
Derek.
Concept Match
Match the Concurrency Fundamentals derekmolloy.ie Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.
Definition Pool
Physical simultaneity where multiple computations execute at the exact same instant.
A lightweight unit of execution that lives inside and shares memory with a process.
An isolated execution environment with private memory space and resources.
A structural property where multiple tasks make progress in overlapping time periods.
Submit
Which of the following statements accurately describe the behaviour of thread::spawn() in Rust? derekmolloy.ie
It returns a JoinHandle, which can be used to wait for the thread's completion and retrieve its result.
It automatically ensures that all spawned threads are joined before the main function returns.
It creates a new OS thread and blocks the main thread until the new thread starts running.
It requires a closure that must satisfy the 'static lifetime bound if it does not use scoped threads. Submit Answer
Spawning and Joining Threads derekmolloy.ie Drag snippets from the pool into the blanks so the program produces the output shown, then click Submit.
1 use std::thread;
2
3 fn main() {
4 // Spawn a thread that returns a value
5 let handle = thread:: ····· (|| {
6 42
7 });
8
9 // Wait for the thread to finish and retrieve the result
10 let result = handle. ····· ().unwrap();
11 println!("Thread returned: {}", result);
12 }
Available Snippets
wait
run
await
create
join
spawn
Submit
Why is the 'move' keyword frequently required when spawning a new thread? derekmolloy.ie
To satisfy the thread-safety requirements of the operating system's kernel-level scheduler.
To prevent the main thread from accessing any variables until the spawned thread finishes.
To tell the compiler to optimise the closure body for faster concurrent execution.
To force the closure to take ownership of captured variables, ensuring they live long enough. Submit Answer
Concept Match
Match the Channel Components derekmolloy.ie Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.
Definition Pool
The transmitting end of a channel; it can be cloned to allow multiple producer threads.
A non-blocking receive method that returns an error immediately if no message is waiting.
Stands for 'Multiple Producer, Single Consumer', the standard channel type in Rust.
The receiving end of a channel; it cannot be cloned, ensuring a single consumer.
Submit
Predict the output: Channel Communication derekmolloy.ie Read the code below, then choose the terminal output it produces and click Submit.
1 use std::sync::mpsc;
2 use std::thread;
3
4 fn main() {
5 let (tx, rx) = mpsc::channel();
6
7 thread::spawn(move || {
8 tx.send(10).unwrap();
9 tx.send(20).unwrap();
10 });
11
12 let val1 = rx.recv().unwrap();
13 let val2 = rx.recv().unwrap();
14 println!("{} {}", val1, val2);
15 }
Submit Answer
When does a loop using a Receiver as an iterator (e.g., for msg in rx { ... }) terminate? derekmolloy.ie
Exactly 60 seconds after the last message was successfully transmitted through the pipe.
As soon as the buffer is empty, regardless of whether senders are still active.
When all corresponding Sender handles have been dropped and the channel buffer is empty.
Only when the developer explicitly calls an rx.close() method from the consumer thread. Submit Answer
In the context of Assignment 2 and responsive GUIs, why is try_recv() preferred over recv() inside the update() loop? derekmolloy.ie
Because recv() is a blocking call that would freeze the GUI until a new message arrives.
Because recv() requires a mutable reference to the context, which is not available in egui.
Because try_recv() automatically handles the synchronisation of background hardware threads.
Because try_recv() is significantly faster at processing complex data structures like JSON. Submit Answer
Concept Match
Match the Synchronisation Primitives derekmolloy.ie Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.
Definition Pool
An Atomic Reference Counted pointer that enables multiple threads to share ownership of data.
A smart pointer that provides data access and automatically releases the lock when dropped.
Enforces mutual exclusion, allowing only one thread at a time to access the protected data.
Allows multiple concurrent readers or exactly one exclusive writer; ideal for read-heavy data.
Submit
Drag snippets from the pool into the blanks so the program produces the output shown, then click Submit.
1 use std::sync::{Arc, Mutex};
2 use std::thread;
3
4 fn main() {
5 // Create a shared counter
6 let counter = Arc::new(Mutex::new(0));
7 let mut handles = vec![];
8
9 for _ in 0..10 {
10 // Clone the Arc to share ownership
11 let counter_clone = Arc:: ····· (&counter);
12 let handle = thread::spawn(move || {
13 // Acquire the lock
14 let mut num = counter_clone. ····· ().unwrap();
15 *num += 1;
16 });
17 handles.push(handle);
18 }
19 }
Available Snippets
read
acquire
clone
lock
new
copy
Submit
What is 'Mutex Poisoning' in Rust? derekmolloy.ie
A hardware failure where the CPU fails to correctly execute an atomic compare-and-swap instruction.
An optimisation where the compiler permanently locks a mutex to prevent any further modifications.
A state where a thread panics while holding a lock, indicating the protected data may be inconsistent.
A security vulnerability where an external process injects malicious code into a shared memory region. Submit Answer
Why is Arc<T> used instead of Rc<T> for sharing data between threads? derekmolloy.ie
Because Rc is restricted to sharing only primitive types like integers and booleans.
Because Rc uses non-atomic counters which could lead to data races on the reference count itself.
Because Arc allows the data to be stored in the program's read-only binary section.
Because Arc uses atomic operations to update the reference count, ensuring it is thread-safe. Submit Answer
Concept Match
Match the Advanced Sync Concepts derekmolloy.ie Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.
Definition Pool
A thread-safe boolean that can be loaded and stored without the overhead of a mutex lock.
The strongest memory ordering, ensuring a consistent global order of atomic operations.
Allows a thread to sleep efficiently until another thread signals that a condition has changed.
A situation where two threads are each waiting for a lock held by the other, stalling indefinitely.
Submit
Using an Atomic Stop Flag derekmolloy.ie Drag snippets from the pool into the blanks so the program produces the output shown, then click Submit.
1 use std::sync::atomic::{AtomicBool, Ordering};
2
3 fn main() {
4 let stop_flag = AtomicBool::new(false);
5
6 // Set the flag atomically
7 stop_flag. ····· (true, Ordering::SeqCst);
8
9 // Read the flag atomically
10 if stop_flag. ····· (Ordering::SeqCst) {
11 println!("Stopping...");
12 }
13 }
Submit
In a read-heavy workload where 100 threads read a value and only 1 thread writes it, why is RwLock<T> superior to Mutex<T>? derekmolloy.ie
Because RwLock uses a more advanced hardware-level cache that is only available on multi-core ARM processors.
Because RwLock allows all 100 readers to access the data simultaneously, whereas Mutex would serialise them.
Because RwLock provides a compile-time guarantee that the writer thread will always have highest priority.
Because Mutex requires a separate memory allocation for every reader thread that attempts to acquire the lock. Submit Answer
Which of the following describes 'Priority Inversion'? derekmolloy.ie
A situation where a high-priority thread is blocked by a low-priority thread holding a shared resource.
An optimisation where the OS scheduler prioritises background threads to save battery life.
A logic error where a thread's priority is accidentally set to a negative value by the developer.
A scenario where the main thread is forced to wait for all spawned threads to finish before exiting. Submit Answer
Concept Match
Match the Marker Traits derekmolloy.ie Drag each definition into its matching concept slot, then click Submit. Tap × to return a placed card to the pool.
Definition Pool
A trait with no methods, used purely to provide information to the compiler.
A type that can safely have its ownership transferred between thread boundaries.
Types like Mutex or Atomic that allow mutation even when accessed via an immutable reference.
A type that can safely be shared via references (&T) across multiple threads.
Submit
Why does the Rust compiler refuse to move an Rc<T> into a spawned thread? derekmolloy.ie
Because Rc<T> does not implement the Send trait due to its use of non-atomic reference counting.
Because Rc<T> is too large to fit in the new thread's stack space without causing an overflow.
Because moving Rc<T> could lead to two threads updating the same counter simultaneously, causing a data race.
Because the thread::spawn function is hard-coded to only accept String and integer types. Submit Answer
Regarding the relationship between Send and Sync, which of the following is TRUE? derekmolloy.ie
If a type is Send, it is guaranteed to be Sync, as ownership transfer is more restrictive.
The Sync trait is required for any data being sent through an mpsc channel.
A type T is Sync if and only if a reference to it (&T) is Send.
Any type that implements Sync must also explicitly implement the Copy trait. Submit Answer
Which of the following types are NOT Send or Sync and require 'unsafe' code or a Mutex to be used in threads? Select all that apply. derekmolloy.ie
RefCell<T>, as its runtime borrow checks are not thread-safe.
AtomicU32, as it provides hardware-level synchronisation for its internal value.
String, as it is a complex heap-allocated type that requires strict management.
Raw pointers like *mut u8, as they carry no ownership or safety information. Submit Answer
Congratulations on completing the Chapter 10 Knowledge Test!
Review any questions you missed to ensure a solid grasp of Rust’s ‘fearless concurrency’ model before moving on to networking and advanced edge patterns.