> Как работает дедлок и как его избежать (iOS, Swift)
Уровень: senior · Роль: mobile · Категория: Технические вопросы
Компании: Axel Pro
Стек: iOS, Swift
> Пример ответа
Короткий ответ
Дедлок - это состояние, когда два или более потока блокируют друг друга, ожидая ресурсы, удерживаемые другими потоками, и ни один не может продолжить выполнение. В iOS-разработке чаще всего встречается при работе с NSLock, DispatchQueue.sync или os_unfair_lock. Основные способы избежать: не вкладывать блокировки, использовать единый порядок захвата, избегать sync на той же очереди, применять DispatchQueue.async или os_unfair_lock вместо NSLock там, где это возможно.
Подробное объяснение
Дедлок возникает при выполнении четырёх условий Коффмана:
- Взаимное исключение - ресурс может быть занят только одним потоком.
- Удержание и ожидание - поток удерживает ресурс и ждёт другой.
- Отсутствие вытеснения - ресурс нельзя принудительно забрать.
- Циклическое ожидание - существует цикл потоков, каждый из которых ждёт ресурс, удерживаемый следующим.
В iOS-контексте классический пример - вызов DispatchQueue.main.sync из главной очереди или вложенные блокировки:
SWIFTlet lockA = NSLock()let lockB = NSLock()// Поток 1lockA.lock()lockB.lock() // ждёт lockB// Поток 2lockB.lock()lockA.lock() // ждёт lockA
Оба потока блокируются навсегда. Также дедлок возможен при использовании DispatchQueue.sync на последовательной очереди, если вызвать её изнутри той же очереди.
На практике
В реальной iOS-разработке дедлоки чаще всего возникают:
- при синхронном вызове на главной очереди из главного потока;
- при использовании нескольких
NSLockв разном порядке; - при работе с
DispatchSemaphoreвнутри той же очереди; - при использовании
OperationQueueс зависимостями, образующими цикл.
Практические рекомендации:
- Не вызывайте
syncна той же очереди - используйтеasyncили проверяйтеThread.isMainThread. - Фиксируйте порядок захвата блокировок - если всегда захватывать
lockAпередlockB, цикл невозможен. - Используйте
os_unfair_lockилиNSLockс минимальной критической секцией - чем меньше код под блокировкой, тем меньше шанс пересечения. - Применяйте
DispatchQueueс барьерами (queue.async(flags: .barrier)) для read-write паттернов вместо ручных блокировок. - Избегайте вложенных блокировок - если возможно, реструктурируйте код.
- Используйте таймауты для
DispatchSemaphore(wait(timeout:)), чтобы не блокироваться вечно.
Пример кода
Дедлок на главной очереди:
SWIFT// Вызов из главного потокаDispatchQueue.main.sync {// никогда не выполнится - дедлок}
Исправление:
SWIFTif Thread.isMainThread {// выполняем код напрямуюupdateUI()} else {DispatchQueue.main.async {updateUI()}}
Дедлок с двумя блокировками:
SWIFTlet lockA = NSLock()let lockB = NSLock()// Поток 1lockA.lock()lockB.lock()// ...lockB.unlock()lockA.unlock()// Поток 2 - тот же порядок захватаlockA.lock()lockB.lock()// ...lockB.unlock()lockA.unlock()
Безопасный вариант с единым порядком - дедлок невозможен, даже если потоки выполняются параллельно.
Как отвечать на собеседовании
Начните с краткого определения и четырёх условий Коффмана. Затем приведите конкретный пример из iOS - DispatchQueue.main.sync или вложенные NSLock. Покажите, как диагностировать дедлок: использование lldb с bt (backtrace) для всех потоков, DispatchQueue.main в стеке, застывшие потоки. Затем перечислите стратегии предотвращения: единый порядок захвата, избегание sync, таймауты, барьеры. Завершите примером кода с исправлением.
Что проверяет интервьюер
- понимание модели памяти и многопоточности в iOS;
- знание GCD и
NSLock/os_unfair_lock; - умение анализировать условия возникновения дедлока;
- способность предложить практическое решение, а не только теорию;
- знание инструментов диагностики (Xcode, Instruments,
lldb).
Типичные ошибки
- ответ только про
DispatchQueue.main.sync, без упоминания блокировок; - незнание условий Коффмана;
- предложение использовать
asyncвсегда, без учёта гонок данных; - игнорирование таймаутов и
os_unfair_lock; - путаница между дедлоком, гонкой данных и priority inversion;
- отсутствие примера кода или некорректный пример с
syncна глобальной очереди (это не дедлок).
> Похожие задачи по mobile
Что копируется, а что передается по ссылке в Swift
На каких архитектурах писали и какие плюсы и минусы вы видите
Какие средства синхронизации потоков существуют: mutex, semaphore, NSLock
Какие механизмы синхронизации существуют для решения проблем многопоточности
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью