CPP Concurrency & Multithreading 3 — Questions and Answers
Question 1: What is a data race in C++?
- Two threads competing to finish a computation first
- Two threads simultaneously accessing the same memory location where at least one access is a write and neither is synchronized (Correct answer)
- A race condition in which thread scheduling determines program correctness
- A situation where two threads deadlock while accessing the same data
Correct answer: Two threads simultaneously accessing the same memory location where at least one access is a write and neither is synchronized
A data race is undefined behavior in C++ and occurs when two or more threads concurrently access the same memory location without synchronization, with at least one write.
Question 2: Which memory order provides the strongest synchronization guarantee in C++?
- `std::memory_order_relaxed`
- `std::memory_order_acquire`
- `std::memory_order_release`
- `std::memory_order_seq_cst` (Correct answer)
Correct answer: `std::memory_order_seq_cst`
`std::memory_order_seq_cst` (sequentially consistent) is the default and strongest ordering, ensuring a single total order of operations across all threads.
Question 3: What does `std::async` return?
- `std::thread`
- `std::promise`
- `std::future` (Correct answer)
- `std::packaged_task`
Correct answer: `std::future`
`std::async` launches a callable asynchronously (or deferred) and returns a `std::future` object through which the result can be retrieved.
Question 4: What is the purpose of `std::promise` in C++ concurrency?
- To automatically schedule tasks on a thread pool
- To provide a one-time channel for passing a value or exception from a producer thread to a consumer via an associated `std::future` (Correct answer)
- To synchronize two threads at a barrier point
- To lock a mutex conditionally based on a boolean predicate
Correct answer: To provide a one-time channel for passing a value or exception from a producer thread to a consumer via an associated `std::future`
`std::promise` is one end of a future-promise pair: the promise sets a value or exception, and the associated `std::future` retrieves it, enabling one-time inter-thread communication.
Question 5: What is `std::call_once` used for?
- Ensuring a function executes exactly once across all threads, even with concurrent calls (Correct answer)
- Executing a function once per thread during thread initialization
- Calling a function with a timeout to prevent blocking
- Registering a cleanup function to run when a thread exits
Correct answer: Ensuring a function executes exactly once across all threads, even with concurrent calls
`std::call_once` with a `std::once_flag` guarantees that a callable is executed exactly once, even if multiple threads call it simultaneously — useful for thread-safe lazy initialization.
Question 6: What is false sharing in multithreaded programs?
- When threads accidentally share the same mutex object
- When two threads modify different variables that reside on the same cache line, causing unnecessary cache invalidation (Correct answer)
- When a thread reads stale data because another thread's write is not yet visible
- When the OS falsely reports that a thread is waiting when it is actually running
Correct answer: When two threads modify different variables that reside on the same cache line, causing unnecessary cache invalidation
False sharing occurs when variables used by different threads share a cache line; writes by one thread invalidate the entire line for others, degrading performance.
Question 7: Which C++ feature enables lock-free programming by allowing atomic read-modify-write operations?
- `std::mutex::try_lock()`
- `std::atomic::compare_exchange_strong()` (Correct answer)
- `std::condition_variable::notify_all()`
- `std::shared_lock`
Correct answer: `std::atomic::compare_exchange_strong()`
`compare_exchange_strong()` atomically compares the stored value to an expected value and, if equal, replaces it with a desired value — the core operation for building lock-free data structures.
What is a data race in C++?