Если вызвать дважды
lock() на одном и том же объекте std::mutex из одного и того же потока, это приведет к взаимной блокировке (deadlock). Это происходит потому, что после первого вызова lock() мьютекс уже будет заблокирован данным потоком, и второй вызов lock() будет ожидать освобождения мьютекса, что никогда не произойдет, так как поток уже заблокировал мьютекс.#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void threadFunction() {
mtx.lock(); // Первый вызов lock()
std::cout << "Locked once" << std::endl;
// Попытка повторного захвата того же мьютекса приведет к взаимной блокировке
mtx.lock(); // Второй вызов lock() - Deadlock
std::cout << "Locked twice" << std::endl;
mtx.unlock();
mtx.unlock();
}
int main() {
std::thread t(threadFunction);
t.join();
return 0;
}
🚩Как избежать взаимной блокировки
🟠Использование `std::recursive_mutex`: Этот тип мьютекса позволяет одному и тому же потоку захватывать мьютекс несколько раз без блокировки. Но следует использовать его осторожно, так как он может скрывать логические ошибки в коде.
#include <iostream>
#include <thread>
#include <mutex>
std::recursive_mutex rec_mtx;
void threadFunction() {
rec_mtx.lock(); // Первый вызов lock()
std::cout << "Locked once" << std::endl;
rec_mtx.lock(); // Второй вызов lock()
std::cout << "Locked twice" << std::endl;
rec_mtx.unlock();
rec_mtx.unlock();
}
int main() {
std::thread t(threadFunction);
t.join();
return 0;
}
🟠Использование `std::unique_lock` или `std::lock_guard`: Эти обертки автоматически управляют блокировкой и разблокировкой мьютекса, обеспечивая корректное использование мьютексов.
#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void threadFunction() {
std::lock_guard<std::mutex> lock(mtx); // Автоматическая блокировка
std::cout << "Locked once" << std::endl;
// Повторный вызов lock() не требуется, так как lock_guard управляет мьютексом
}
int main() {
std::thread t(threadFunction);
t.join();
return 0;
}
🟠Проверка состояния мьютекса с помощью `try_lock()`: Метод
try_lock() пытается захватить мьютекс и возвращает false, если мьютекс уже захвачен, что предотвращает взаимную блокировку.#include <iostream>
#include <thread>
#include <mutex>
std::mutex mtx;
void threadFunction() {
if (mtx.try_lock()) { // Попытка захвата мьютекса
std::cout << "Locked once" << std::endl;
if (mtx.try_lock()) { // Попытка повторного захвата
std::cout << "Locked twice" << std::endl;
mtx.unlock();
}
mtx.unlock();
}
}
int main() {
std::thread t(threadFunction);
t.join();
return 0;
Ставь 👍 и забирай 📚 Базу знаний