> Сколько минимум потоков нужно для дедлока? (iOS, Swift)
Уровень: senior · Роль: mobile · Категория: Технические вопросы
Компании: Сбер
Стек: iOS, Swift
> Пример ответа
Короткий ответ
Минимум два потока. Дедлок - это ситуация, когда каждый поток удерживает ресурс и ждёт ресурс, удерживаемый другим потоком. Один поток не может создать классический deadlock, потому что ему не с кем конкурировать за ресурсы. Однако на практике в iOS дедлок может возникнуть и с одним потоком, если использовать DispatchQueue.main.sync из самой main queue - это частный случай, который называют "deadlock на одной очереди".
Подробное объяснение
Классический deadlock требует как минимум двух потоков и двух ресурсов. Условия Коффмана: mutual exclusion, hold and wait, no preemption, circular wait. При двух потоках circular wait выполняется тривиально: поток A держит ресурс 1 и ждёт ресурс 2, поток B держит ресурс 2 и ждёт ресурс 1.
В контексте GCD и Swift deadlock возможен и на одном потоке, но это не классический deadlock, а скорее "self-deadlock": вызов DispatchQueue.main.sync внутри main queue блокирует очередь, которая ждёт саму себя. Формально это тоже circular wait, но с одним участником.
Для senior-позиции важно различать:
- классический deadlock между несколькими потоками (минимум 2)
- self-deadlock на одной serial queue (1 поток)
- livelock и starvation - смежные проблемы, но не deadlock
На практике
В iOS-разработке deadlock чаще всего встречается при неправильном использовании GCD:
DispatchQueue.main.syncиз main thread- вложенные
syncвызовы на одной serial queue - блокировки
NSLockилиos_unfair_lockв неправильном порядке
Для диагностики используйте Thread Sanitizer в Xcode - он детектирует data races и deadlocks. Также полезно правило: никогда не вызывайте sync на очереди, которая может быть текущей.
Пример кода
SWIFT// Классический deadlock с двумя потокамиlet lock1 = NSLock()let lock2 = NSLock()let threadA = Thread {lock1.lock()Thread.sleep(forTimeInterval: 0.1)lock2.lock() // ждёт lock2, который держит threadBlock2.unlock()lock1.unlock()}let threadB = Thread {lock2.lock()Thread.sleep(forTimeInterval: 0.1)lock1.lock() // ждёт lock1, который держит threadAlock1.unlock()lock2.unlock()}threadA.start()threadB.start()// Self-deadlock на main queueDispatchQueue.main.async {DispatchQueue.main.sync { // deadlockprint("never reached")}}
Как отвечать на собеседовании
Начните с короткого ответа "два потока", затем уточните про self-deadlock на одной очереди. Покажите понимание условий Коффмана. Для senior-уровня добавьте рассуждение о том, почему один поток недостаточен: нет конкуренции за ресурсы, circular wait невозможен. Упомяните, что в iOS с GCD deadlock возможен и на одном потоке, но это исключение из правил.
Что проверяет интервьюер
- понимание базовых концепций конкурентности
- умение различать классический deadlock и self-deadlock
- знание GCD и его подводных камней
- способность рассуждать о причинах и условиях deadlock
- практический опыт отладки подобных проблем
Типичные ошибки
- ответ "один поток" без пояснения про self-deadlock
- путаница между deadlock и race condition
- утверждение, что deadlock возможен без блокировок (это неверно для классического определения)
- игнорирование контекста GCD при ответе
- отсутствие упоминания условий Коффмана для senior-уровня
> Похожие задачи по mobile
Как исключить объект из responder chain?
От какого класса наследуется UIButton?
Является ли порядок вывода гарантированным или вероятным
Что делает механизм ARC на этапе компиляции
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью