Ответ
Повторная попытка захватить нерекурсивный мьютекс (std::mutex) в одном и том же потоке приводит к неопределённому поведению (Undefined Behavior, UB). На практике это чаще всего вызывает взаимную блокировку (deadlock), так как поток бесконечно ждёт сам себя.
#include <mutex>
std::mutex mtx;
void risky_function() {
mtx.lock(); // Первый захват – OK.
// ... какая-то работа ...
mtx.lock(); // ВТОРОЙ захват в том же потоке – НЕОПРЕДЕЛЁННОЕ ПОВЕДЕНИЕ (deadlock!).
mtx.unlock();
mtx.unlock();
}
Решение: Для сценариев, где один поток может нуждаться в многократном захвате одного и того же мьютекса, используйте рекурсивный мьютекс std::recursive_mutex.
#include <mutex>
std::recursive_mutex rec_mtx;
void safe_recursive_function(int depth) {
rec_mtx.lock(); // Захват 1 (или N) – OK.
// ... работа ...
if (depth > 0) {
safe_recursive_function(depth - 1); // Рекурсивный вызов снова захватит мьютекс.
}
rec_mtx.unlock(); // Каждому lock() должен соответствовать unlock().
}
Важно: Использование std::recursive_mutex часто указывает на проблему с дизайном кода. По возможности следует пересматривать структуру функций и область блокировки, чтобы избежать необходимости в рекурсивных блокировках.