🤔 Что будет если вызвать дважды lock()?



Если вызвать дважды 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;

}




Ставь 👍 и забирай 📚 Базу знаний