Назад к вопросам
Middle+
103
questionbank
Как работает механизм атомарного залочивания двух мьютексов?
Sobes Copilot
Получайте ответы в реальном времени
Ответ от нейросети
sobes.tech AI
Для корректной атомарной блокировки двух мьютексов используется функция std::lock. Она гарантирует, что либо оба мьютекса будут успешно заблокированы, либо ни один из них.
Алгоритм std::lock следующий:
- Пытается заблокировать первый мьютекс.
- Если успешно, пытается заблокировать второй мьютекс.
- Если второй мьютекс также успешно заблокирован, оба мьютекса остаются заблокированными.
- Если заблокировать второй мьютекс не удалось (например, он уже заблокирован другим потоком), то блокировка с первого мьютекса снимается, и функция ждет, пока оба мьютекса станут свободными, затем повторяет попытку.
Это предотвращает взаимные блокировки (deadlock), которые могли бы возникнуть при последовательной блокировке вручную:
// Пример ошибки:
std::mutex m1, m2;
void func1() {
m1.lock();
m2.lock(); // Может вызвать deadlock, если другой поток уже заблокировал m2 и ждет m1
// ... работа с защищенными ресурсами
m2.unlock();
m1.unlock();
}
void func2() {
m2.lock();
m1.lock(); // Может вызвать deadlock
// ... работа с защищенными ресурсами
m1.unlock();
m2.unlock();
}
С использованием std::lock:
#include <mutex>
std::mutex m1, m2;
void safe_func() {
std::lock(m1, m2); // Атомарная блокировка обоих мьютексов
// ... работа с защищенными ресурсами
// Освобождение мьютексов в обратном порядке или с помощью lock_guard
m2.unlock();
m1.unlock();
}
Более предпочтительный способ с использованием std::unique_lock и std::adopt_lock:
#include <mutex>
#include <unique_lock>
std::mutex m1, m2;
void safe_func_with_guards() {
std::lock(m1, m2); // Атомарная блокировка
std::unique_lock<std::mutex> lock1(m1, std::adopt_lock); // Связываем lock_guard с уже заблокированным мьютексом
std::unique_lock<std::mutex> lock2(m2, std::adopt_lock); // Связываем lock_guard с уже заблокированным мьютексом
// Теперь мьютексы будут автоматически разблокированы при выходе из области видимости
// ... работа с защищенными ресурсами
}
Использование std::lock с std::unique_lock является наилучшей практикой, так как гарантирует правильное освобождение мьютексов даже при исключениях.