В современном C++ (начиная с C++11) существует богатый инструментарий для работы с многопоточностью: std::thread, мьютексы и различные объекты-обёртки для управления доступом к ресурсам. Безопасное взаимодействие между потоками требует понимания следующих компонентов:
Чтобы избежать гонок, всегда используйте RAII-обёртки там, где возможно. Учтите, что попытка повторно захватить тот же мьютекс приведёт к deadlock (если это не рекурсивный мьютекс).
Пример корректной работы:
#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(); }
Можно ли использовать std::lock_guardstd::mutex для реализации условной синхронизации с std::condition_variable?
Ответ: Нет! Для работы с std::condition_variable обязательно нужен std::unique_lockstd::mutex, потому что lock_guard не предоставляет методов для контроля блокировки (например, временно отпустить — unlock — и потом снова захватить), которые необходимы при ожидании уведомления.
Пример:
std::mutex mtx; std::condition_variable cv; bool ready = false; void waitForEvent() { std::unique_lock<std::mutex> lock(mtx); cv.wait(lock, []{return ready;}); // Дальнейшая обработка }
История
В проекте использовалась ручная работа с mtx.lock()/mtx.unlock(). При выбрасывании исключения между lock/unlock мьютекс оставался заблокированным — множество потоков "подвисали". После замены на RAII (
std::lock_guard) проблема исчезла.
История
При оповещении через std::condition_variable вместо std::unique_lock использовали std::lock_guard. В результате, программа не компилировалась на новых компиляторах, а на старом — происходил runtime assert из-за несогласованного API.
История
В коде вызывался unlock() у std::lock_guard для "ручного" контроля доступа к мьютексу. Это приводило к неопределённому поведению на разных компиляторах, иногда к падению приложения. Было понято, что lock_guard не поддерживает manual release, нужна migration к unique_lock.