Механизм атомарного залочивания двух mutex
Атомарное залочивание двух (или более) мьютексов — это сложная задача, поскольку неправильная реализация может привести к взаимоблокировке (deadlock). Взаимоблокировка возникает, когда два потока ждут освобождения мьютексов, которые друг у друга заняты. Для решения этой проблемы используется несколько методов. Один из них — использование стандартной функции `std::lock` из C++11, которая позволяет атомарно залочить несколько мьютексов.
std::lock
Гарантирует, что все переданные ей мьютексы будут залочены без возможности возникновения взаимоблокировки. Если один из мьютексов не может быть залочен, функция разблокирует уже захваченные мьютексы и начнет попытку захвата заново.
Пример кода:
```cpp
#include <iostream>
#include <thread>
#include <mutex>
std::mutex m1, m2;
void threadFunction1() {
std::lock(m1, m2); // атомарное залочивание
std::lock_guard<std::mutex> lg1(m1, std::adopt_lock);
std::lock_guard<std::mutex> lg2(m2, std::adopt_lock);
// Критическая секция
std::cout << "Thread 1 has locked both mutexes" << std::endl;
// мьютексы автоматически разблокируются при выходе из области видимости
}
void threadFunction2() {
std::lock(m1, m2); // атомарное залочивание
std::lock_guard<std::mutex> lg1(m1, std::adopt_lock);
std::lock_guard<std::mutex> lg2(m2, std::adopt_lock);
// Критическая секция
std::cout << "Thread 2 has locked both mutexes" << std::endl;
// мьютексы автоматически разблокируются при выходе из области видимости
}
int main() {
std::thread t1(threadFunction1);
std::thread t2(threadFunction2);
t1.join();
t2.join();
return 0;
}
```
Объяснение кода:
1. std::lock(m1, m2): Эта функция пытается залочить оба мьютекса одновременно. Если это не удается (например, если один мьютекс уже захвачен другим потоком), то освобождаются все захваченные мьютексы и начинается новая попытка захвата.
2. std::lock_guard<std::mutex> lg1(m1, std::adopt_lock): Эта конструкция создает объект `std::lock_guard`, который автоматически разблокирует мьютекс при выходе из области видимости. Параметр `std::adopt_lock` указывает, что мьютекс уже захвачен и не должен быть захвачен повторно.
3. Критическая секция: Между захватом и освобождением мьютексов располагается код, который должен выполняться безопасно в многопоточной среде.
Для атомарного захвата двух мьютексов используется функция `std::lock`, которая предотвращает взаимоблокировки. Это позволяет безопасно управлять ресурсами в многопоточной среде.
May 24, 2024, easyoffer