← Назад ко всем вопросам

Какой механизм может атомарно заблокировать два мьютекса

1️⃣ Как кратко ответить

Для атомарной блокировки двух мьютексов в C++ используется функция std::lock. Она гарантирует, что оба мьютекса будут заблокированы без взаимоблокировки (deadlock).

2️⃣ Подробное объяснение темы

В многопоточных приложениях часто возникает необходимость синхронизации доступа к общим ресурсам. Мьютексы (mutexes) — это один из основных инструментов для управления доступом к таким ресурсам. Однако, когда требуется заблокировать более одного мьютекса одновременно, существует риск взаимоблокировки (deadlock), если блокировки выполняются в неправильном порядке.

Функция std::lock из стандартной библиотеки C++ решает эту проблему, предоставляя механизм для атомарной блокировки нескольких мьютексов. Она принимает произвольное количество мьютексов и блокирует их все одновременно, гарантируя, что не произойдет взаимоблокировки.

Пример использования std::lock:

#include <iostream>
#include <thread>
#include <mutex>
​
// Два мьютекса для синхронизации доступа к ресурсам
std::mutex mutex1;
std::mutex mutex2;
​
// Функция, которая будет выполняться в потоке
void threadFunction(int id) {
    // Атомарная блокировка двух мьютексов
    std::lock(mutex1, mutex2);
​
    // Использование std::lock_guard для автоматического освобождения мьютексов
    std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock);
​
    // Критическая секция, где доступ к ресурсам защищен
    std::cout << "Thread " << id << " has locked both mutexes." << std::endl;
​
    // Мьютексы будут автоматически освобождены при выходе из области видимости
}
​
int main() {
    // Создание двух потоков, которые будут выполнять функцию threadFunction
    std::thread t1(threadFunction, 1);
    std::thread t2(threadFunction, 2);
​
    // Ожидание завершения потоков
    t1.join();
    t2.join();
​
    return 0;
}

Разбор кода:

  • std::mutex mutex1; и std::mutex mutex2;: Объявление двух мьютексов, которые будут использоваться для синхронизации доступа к ресурсам.

  • void threadFunction(int id): Функция, которая будет выполняться в каждом потоке. Она принимает идентификатор потока для вывода информации.

  • std::lock(mutex1, mutex2);: Атомарная блокировка обоих мьютексов. Эта функция гарантирует, что оба мьютекса будут заблокированы без риска взаимоблокировки.

  • std::lock_guard<std::mutex> lock1(mutex1, std::adopt_lock); и std::lock_guard<std::mutex> lock2(mutex2, std::adopt_lock);: Использование std::lock_guard с std::adopt_lock для управления временем жизни мьютексов. std::adopt_lock указывает, что мьютексы уже заблокированы и их не нужно блокировать снова.

  • std::cout << "Thread " << id << " has locked both mutexes." << std::endl;: Критическая секция, где выполняется работа с защищенными ресурсами.

  • t1.join(); и t2.join();: Ожидание завершения потоков, чтобы программа не завершилась до их окончания.

Использование std::lock позволяет избежать сложностей, связанных с ручным управлением порядком блокировки мьютексов, и минимизирует риск взаимоблокировок в многопоточных приложениях.

Тема: Многопоточность / Синхронизация
Стадия: Tech

🔒 Подпишись на бусти автора и стань Алигатором, чтобы получить полный доступ к функционалу сайта и отслеживать свой прогресс!

Твои заметки