Последовательное захватывание безопасно только при общем порядке во всех местах программы. Вызовы с переставленными mutex могут зависнуть; передача одного mutex дважды тоже требует отдельной обработки.
Анализ безопасности блокировок в функции с двумя mutex
Последовательное захватывание безопасно только при общем порядке во всех местах программы. Вызовы с переставленными mutex могут зависнуть; передача одного mutex дважды тоже требует отдельной обработки.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Провести ревью функции calculation, в которой задействованы два объекта std::mutex.
- Оценить, насколько корректно выполнена синхронизация.
- Выявить риск взаимоблокировки (deadlock).
- Предложить надёжный способ одновременного захвата нескольких мьютексов.
void calculation(std::mutex& mxA, std::mutex& mxB, const std::vector<int>& input) {
std::lock_guard<std::mutex> lock1(mxA);
std::lock_guard<std::mutex> lock2(mxB);
// расчёт данных
}
Ответ
Последовательное захватывание безопасно только при общем порядке во всех местах программы. Вызовы с переставленными mutex могут зависнуть; передача одного mutex дважды тоже требует отдельной обработки.
Вариант с поддержкой одинаковых аргументов:
std::unique_lock<std::mutex> first(mxA, std::defer_lock);
std::unique_lock<std::mutex> second(mxB, std::defer_lock);
if (&mxA == &mxB) first.lock();
else std::lock(first, second);
// Дальше защищённый расчёт в этой же области видимости.
Для гарантированно разных mutex в C++17 достаточно std::scoped_lock lock(mxA, mxB);. RAII освобождает захваченные блокировки при выходе и исключении. const-ссылка input сама по себе не запрещает другим потокам менять исходный vector; они должны соблюдать тот же протокол защиты.