How does a mutex work in C++, and what must an application do for it to protect shared state correctly?
Explain the language-level guarantee, a possible implementation of an uncontended versus contended lock, and a short C++ example that increments shared state safely. Discuss what goes wrong when only some accesses follow the locking rule.
### Constraints & Assumptions
- Use `std::mutex` and ordinary C++ threads.
- The shared state is a non-atomic counter accessed by more than one thread.
- Assume the mutex and counter remain alive until all worker threads have finished.
- Distinguish standard guarantees from implementation choices; do not assume a particular operating-system primitive, fairness policy, or spin duration.
### Clarifying Questions to Ask
- Must the protected state satisfy an invariant across several fields, or is it just one counter?
- Can code in the critical section throw or return early?
- Can the operation acquire another mutex, or re-enter a function that takes the same mutex?
```hint Ownership and visibility are separate concerns
Explain both why two threads cannot own the same mutex at once and why a later owner can observe writes made by an earlier owner.
```
### What a Strong Answer Covers
- Mutual exclusion and the synchronization relationship between unlock and subsequent successful lock operations on the same mutex.
- A shared locking discipline for every conflicting access to the non-atomic state.
- RAII with `std::lock_guard` or `std::unique_lock`, including exception safety.
- The distinction between a possible atomic fast path and operating-system-assisted blocking under contention.
- Deadlock, non-recursive ownership, and the absence of a portable fairness guarantee.
### Follow-up Questions
- How would you safely lock two mutexes needed by one operation?
- When would `std::unique_lock` be more appropriate than `std::lock_guard`?
Overview: Explain C++ mutex ownership, memory visibility, RAII locking, contention, and deadlock prevention with a shared-counter example.
How does a mutex work in C++, and what must an application do for it to protect shared state correctly?
Explain the language-level guarantee, a possible implementation of an uncontended versus contended lock, and a short C++ example that increments shared state safely. Discuss what goes wrong when only some accesses follow the locking rule.
Constraints & Assumptions
Use
std::mutex
and ordinary C++ threads.
The shared state is a non-atomic counter accessed by more than one thread.
Assume the mutex and counter remain alive until all worker threads have finished.
Distinguish standard guarantees from implementation choices; do not assume a particular operating-system primitive, fairness policy, or spin duration.
Clarifying Questions to Ask Guidance
Must the protected state satisfy an invariant across several fields, or is it just one counter?
Can code in the critical section throw or return early?
Can the operation acquire another mutex, or re-enter a function that takes the same mutex?
What a Strong Answer Covers Guidance
Mutual exclusion and the synchronization relationship between unlock and subsequent successful lock operations on the same mutex.
A shared locking discipline for every conflicting access to the non-atomic state.
RAII with
std::lock_guard
or
std::unique_lock
, including exception safety.
The distinction between a possible atomic fast path and operating-system-assisted blocking under contention.
Deadlock, non-recursive ownership, and the absence of a portable fairness guarantee.
Follow-up Questions Guidance
How would you safely lock two mutexes needed by one operation?
When would
std::unique_lock
be more appropriate than
std::lock_guard
?