In modern C++ (starting from C++11), there is a rich toolkit for working with multithreading: std::thread, mutexes, and various wrapper objects for managing resource access. Safe interaction between threads requires understanding the following components:
To avoid races, always use RAII wrappers where possible. Note that attempting to reacquire the same mutex will lead to deadlock (unless it is a recursive mutex).
Example of correct usage:
#include <iostream> #include <mutex> #include <thread> std::mutex mtx; void printThreadSafe(int id) { std::lock_guard<std::mutex> lock(mtx); std::cout << "Thread " << id << std::endl; } int main() { std::thread t1(printThreadSafe, 1); std::thread t2(printThreadSafe, 2); t1.join(); t2.join(); }
Can std::lock_guardstd::mutex be used to implement conditional synchronization with std::condition_variable?
Answer: No! To work with std::condition_variable, std::unique_lockstd::mutex is necessary, because lock_guard does not provide methods for controlling the lock (for example, temporarily releasing — unlock — and then re-acquiring), which are required when waiting for a notification.
Example:
std::mutex mtx; std::condition_variable cv; bool ready = false; void waitForEvent() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{return ready;}); // Further processing }
Story
The project used manual handling with mtx.lock()/mtx.unlock(). When an exception was thrown between lock/unlock, the mutex remained locked — multiple threads "hung". After switching to RAII (
std::lock_guard), the problem disappeared.
Story
When notifying via std::condition_variable, std::lock_guard was used instead of std::unique_lock. As a result, the program did not compile on new compilers, while on the old one, a runtime assert occurred due to inconsistent API.
Story
The code called unlock() on std::lock_guard for "manual" control over access to the mutex. This led to undefined behavior on different compilers, sometimes crashing the application. It was understood that lock_guard does not support manual release, migration to unique_lock was needed.