CPP Concurrency & Multithreading 2 — Questions and Answers
Question 1: Which C++ standard introduced `std::atomic` and the memory model?
- C++03
- C++11 (Correct answer)
- C++14
- C++17
Correct answer: C++11
C++11 introduced `std::atomic`, `std::thread`, and a formal memory model for concurrent programming.
Question 2: What does `std::memory_order_acquire` guarantee when used in a load operation?
- No memory reordering guarantees are applied
- All subsequent reads/writes in the current thread see effects from the release store they synchronized with (Correct answer)
- All previous reads/writes are flushed to memory before this load
- The load is performed atomically with sequential consistency
Correct answer: All subsequent reads/writes in the current thread see effects from the release store they synchronized with
`memory_order_acquire` ensures that subsequent reads and writes in the current thread cannot be reordered before this load, forming the acquire side of a release-acquire pair.
Question 3: What is a spurious wakeup in the context of `std::condition_variable`?
- A wakeup caused by a signal from another thread calling notify_all
- A wakeup that occurs without any thread calling notify_one or notify_all (Correct answer)
- A wakeup that results in a deadlock
- A wakeup caused by a timeout expiring
Correct answer: A wakeup that occurs without any thread calling notify_one or notify_all
A spurious wakeup is when `wait()` returns without any thread having called `notify_one` or `notify_all`, which is why wait should always be used with a predicate.
Question 4: What is the difference between `std::lock_guard` and `std::unique_lock`?
- `std::lock_guard` supports deferred locking; `std::unique_lock` does not
- `std::unique_lock` supports deferred locking, manual unlock, and timed locking; `std::lock_guard` is a simpler RAII wrapper (Correct answer)
- `std::lock_guard` is movable; `std::unique_lock` is not
- Both are identical except `std::unique_lock` works with recursive mutexes
Correct answer: `std::unique_lock` supports deferred locking, manual unlock, and timed locking; `std::lock_guard` is a simpler RAII wrapper
`std::unique_lock` provides more flexibility including deferred locking, try-locking, timed locking, and manual unlock/relock, while `std::lock_guard` is a lightweight non-movable RAII wrapper.
Question 5: What does `std::thread::detach()` do?
- Blocks the calling thread until the detached thread finishes
- Cancels the thread's execution immediately
- Allows the thread to run independently so its resources are freed automatically upon completion (Correct answer)
- Transfers ownership of the thread to the OS scheduler
Correct answer: Allows the thread to run independently so its resources are freed automatically upon completion
`detach()` separates the thread of execution from the `std::thread` object, allowing the thread to run independently; its resources are reclaimed automatically when it finishes.
Question 6: Which of the following is true about `std::recursive_mutex`?
- It allows multiple threads to lock it simultaneously
- It allows the same thread to lock it multiple times without deadlocking (Correct answer)
- It automatically releases all locks when the owning thread exits
- It is faster than `std::mutex` due to reduced contention
Correct answer: It allows the same thread to lock it multiple times without deadlocking
`std::recursive_mutex` allows the same thread to acquire the lock multiple times; it must be unlocked the same number of times it was locked.
Question 7: What happens if a `std::thread` object is destroyed while it is still joinable?
- The thread is automatically detached
- The thread is automatically joined
- `std::terminate()` is called (Correct answer)
- The thread is placed in a suspended state
Correct answer: `std::terminate()` is called
If a `std::thread` object is destroyed while joinable (neither joined nor detached), `std::terminate()` is called, which typically aborts the program.
Which C++ standard introduced `std::atomic` and the memory model?