Локальный mutex не защищает общую очередь между вызовами. Кроме того, код дважды unlock-ит мьютекс и использует ссылку на элемент после снятия защиты. Сообщение нужно извлечь под общей блокировкой.
Ревью и улучшение функции обработки сообщений из общей очереди
Локальный mutex не защищает общую очередь между вызовами. Кроме того, код дважды unlock-ит мьютекс и использует ссылку на элемент после снятия защиты. Сообщение нужно извлечь под общей блокировкой.
Короткий ответ
Что ответить на собеседовании
Подробный разбор
Ответ с пояснениями
Условие
Необходимо провести ревью функции handle_message, которая читает сообщения из глобальной очереди и передаёт их в длительный расчёт.
- Выявить логические ошибки и потенциальные состояния гонки.
- Предложить и реализовать рефакторинг кода.
- Особое внимание уделить корректному использованию мьютекса: правильному захвату, отпусканию и исключению двойного разблокирования.
std::queue<std::string> g_messages;
void long_calculation_with_message(const std::string& message);
void handle_message() {
std::mutex mutex;
mutex.lock();
if (!g_messages.empty()) {
const std::string& message = g_messages.front();
mutex.unlock();
long_calculation_with_message(message);
mutex.lock();
g_messages.pop();
mutex.unlock();
}
mutex.unlock();
}
Ответ
Локальный mutex не защищает общую очередь между вызовами. Кроме того, код дважды unlock-ит мьютекс и использует ссылку на элемент после снятия защиты. Сообщение нужно извлечь под общей блокировкой.
Все производители и потребители должны использовать один mutex:
std::mutex g_messages_mutex;
void handle_message() {
std::string message;
{
std::lock_guard<std::mutex> lock(g_messages_mutex);
if (g_messages.empty()) return;
message = std::move(g_messages.front());
g_messages.pop();
}
long_calculation_with_message(message);
}
Длительная работа выполняется без блокировки очереди, а RAII исключает двойное освобождение. Если расчёт бросит исключение, сообщение уже извлечено: политика повторов или подтверждения обработки должна быть отдельной частью системы.