Как работает дедлок и как его избежать
Что проверяют
Знаете ли вы, откуда дедлок берётся в реальном iOS-коде, а не только в учебнике про два потока и два ресурса. Следом почти всегда спрашивают, что будет при DispatchQueue.main.sync с главного потока и как с этим обстоят дела в Swift Concurrency.
Как отвечать
Дедлок это состояние, когда потоки ждут друг друга по кругу и ни один не может продолжить. Для него нужны четыре условия Коффмана: взаимное исключение, удержание ресурса во время ожидания другого, отсутствие принудительного отъёма и циклическое ожидание. Сломайте любое, и дедлока не будет.
Типичные источники на iOS:
syncна свою же последовательную очередь:DispatchQueue.main.syncс главного потока илиqueue.syncизнутри задачи той жеqueue. Задача ждёт очередь, а очередь ждёт завершения этой задачи;- повторный захват нерекурсивной блокировки:
NSLockилиos_unfair_lockдважды в одном потоке. Для такого естьNSRecursiveLock, но чаще это признак плохой структуры; - разный порядок захвата: поток A берёт
lock1, потомlock2, поток B наоборот; - семафор в async-коде:
DispatchSemaphore.wait()внутриTaskблокирует поток кооперативного пула, а потоков в нём примерно столько, сколько ядер, и пул может встать целиком.
Как избегать: единый порядок захвата блокировок, async вместо sync там, где можно, короткие критические секции и никаких вызовов чужого кода и колбэков под блокировкой. В Swift Concurrency классического дедлока на акторах нет, потому что акторы реентерабельны, но плата за это другая: после каждого await состояние актора могло измениться. Для диагностики поставьте приложение на паузу в Xcode и посмотрите стеки всех потоков.
Где спотыкаются
Отвечают только определением про два ресурса и не называют ни одного случая из GCD.
Предлагают NSRecursiveLock как универсальное лекарство. Он лечит только повторный захват в одном потоке, а от разного порядка захвата не спасает.
Путают дедлок с инверсией приоритетов. При инверсии высокоприоритетный поток ждёт низкоприоритетный, которому не хватает процессорного времени, и система частично лечит это повышением приоритета. Дедлок сам не разрешится никогда.