> Что происходит при дедлоке в главной очереди в iOS (iOS, Swift)

Уровень: senior · Роль: mobile · Категория: Технические вопросы

Компании: Совкомбанк

Стек: iOS, Swift

> Пример ответа

Короткий ответ

Дедлок в главной очереди - это ситуация, когда main queue заблокирована ожиданием ресурса, который никогда не будет освобождён, потому что освобождение должно произойти в той же очереди. UI перестаёт реагировать на события, приложение выглядит зависшим. Чаще всего возникает при синхронном вызове DispatchQueue.main.sync из самой main queue или при неправильной работе с семафорами и блокировками.

Подробное объяснение

Главная очередь - это serial queue, которая выполняет задачи последовательно. Дедлок возникает, когда задача, выполняющаяся в main queue, синхронно ожидает завершения другой задачи, которая должна быть поставлена в ту же очередь. Поскольку очередь занята текущей задачей, новая задача не может начаться, и обе задачи ждут друг друга бесконечно.

Основные сценарии:

  1. DispatchQueue.main.sync из main queue - классический случай. Вызов sync блокирует текущий поток до завершения переданного блока, но блок не может выполниться, потому что очередь занята.

  2. Взаимная блокировка через семафоры - если в main queue вызывается semaphore.wait(), а сигнал semaphore.signal() должен быть отправлен из задачи, поставленной в ту же очередь.

  3. Блокировки (NSLock, NSRecursiveLock) - если поток main queue пытается захватить lock, который уже удерживается другой задачей в той же очереди, и эта задача не может завершиться.

  4. Вложенные sync-вызовы - когда внутри блока, выполняющегося в main queue, вызывается sync на другую serial queue, которая в свою очередь делает sync обратно на main queue.

Важно понимать, что дедлок в main queue не всегда приводит к крашу - приложение просто перестаёт отвечать. Система может убить процесс через некоторое время (watchdog), но обычно это выглядит как зависание.

На практике

На практике дедлоки в main queue чаще всего встречаются в legacy-коде, где разработчики не осознают, что уже находятся в main queue. Типичные ситуации:

  • Вызов DispatchQueue.main.sync внутри viewDidLoad, viewWillAppear или обработчиков UI-событий.
  • Использование semaphore.wait() в main queue для ожидания завершения сетевого запроса или фоновой задачи.
  • Неправильная работа с DispatchGroup - вызов group.wait() в main queue, пока задачи группы ещё не завершены.

Правильный подход - всегда проверять, находитесь ли вы в main queue, и использовать асинхронные паттерны (completion handlers, async/await, Combine) вместо синхронного ожидания.

Пример кода

SWIFT
// Классический дедлок
DispatchQueue.main.sync {
// Этот блок никогда не выполнится
print("Deadlock")
}
// Дедлок через семафор
let semaphore = DispatchSemaphore(value: 0)
DispatchQueue.main.async {
semaphore.wait() // Блокирует main queue
// Код ниже не выполнится
}
semaphore.signal() // Этот вызов не выполнится, пока main queue заблокирована
// Правильный подход - асинхронное выполнение
DispatchQueue.main.async {
// Работа с UI
}

Как отвечать на собеседовании

Начните с чёткого определения дедлока и его причины - блокировка main queue при синхронном ожидании задачи из той же очереди. Объясните, почему это происходит: serial queue не может выполнить новую задачу, пока текущая не завершена. Приведите конкретные примеры из практики, покажите понимание последствий - зависание UI, срабатывание watchdog. Обязательно упомяните способы диагностики: использование DispatchQueue.main проверки через Thread.isMainThread, инструменты типа Instruments (Time Profiler, Thread Sanitizer). Завершите рассказом о правильных паттернах - async/await, completion handlers, избегание sync-вызовов на main queue.

Что проверяет интервьюер

Интервьюер оценивает:

  • Понимание модели выполнения GCD и serial queues.
  • Умение объяснить, почему возникает взаимная блокировка.
  • Знание конкретных сценариев, приводящих к дедлоку.
  • Способность предложить корректные решения и альтернативы.
  • Понимание разницы между sync и async вызовами.
  • Наличие практического опыта диагностики подобных проблем.

Типичные ошибки

  • Утверждение, что дедлок в main queue приводит к крашу - на самом деле это зависание.
  • Предложение использовать DispatchQueue.main.async как универсальное решение - это не всегда корректно, если нужно дождаться результата.
  • Непонимание разницы между sync и async при работе с main queue.
  • Игнорирование проблемы с семафорами и блокировками - многие кандидаты знают только про main.sync.
  • Отсутствие упоминания современных подходов (async/await, Combine) как альтернативы синхронному ожиданию.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью