> Как работает дедлок и как его избежать (iOS, Swift)

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

Компании: Axel Pro

Стек: iOS, Swift

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

Дедлок (взаимная блокировка) в iOS-разработке на Swift возникает, когда два или более потока (или очереди) ожидают освобождения ресурсов, захваченных друг другом, и ни один из них не может продолжить выполнение. Классический пример - использование семафоров или блокировок (NSLock, os_unfair_lock) в сочетании с GCD.

Как возникает дедлок:

  • Поток A захватывает ресурс 1 и ждет ресурс 2.
  • Поток B захватывает ресурс 2 и ждет ресурс 1.
  • Оба потока блокируются навсегда.

Пример на Swift:

SWIFT
let lock1 = NSLock()
let lock2 = NSLock()
DispatchQueue.global().async {
lock1.lock()
sleep(1) // имитация работы
lock2.lock()
print("Поток 1 выполнен")
lock2.unlock()
lock1.unlock()
}
DispatchQueue.global().async {
lock2.lock()
sleep(1)
lock1.lock()
print("Поток 2 выполнен")
lock1.unlock()
lock2.unlock()
}

Здесь оба потока зависнут.

Как избежать дедлока:

  1. Соблюдать порядок захвата блокировок - всегда захватывать ресурсы в одном и том же порядке (например, сначала lock1, потом lock2). Это самый надежный способ.
  2. Использовать os_unfair_lock (или NSLock с тайм-аутом) - но в Swift нет встроенного тайм-аута для NSLock, поэтому лучше избегать сложных иерархий.
  3. Применять GCD вместо ручных блокировок - использовать последовательные очереди (DispatchQueue) или барьеры (barrier) для синхронизации доступа к данным. Например, через sync на serial queue.
  4. Использовать async/await (Swift Concurrency) - с акторами (actor) дедлоки практически исключены, так как акторы автоматически управляют доступом к своему состоянию.
  5. Избегать вложенных блокировок - если возможно, перепроектировать код так, чтобы не требовалось захватывать несколько ресурсов одновременно.

В iOS-разработке чаще всего дедлоки возникают при неправильном использовании DispatchQueue.main.sync из фоновой очереди (если main уже заблокирован) или при смешивании семафоров с асинхронными вызовами. Лучшая практика - минимизировать ручные блокировки и отдавать предпочтение высокоуровневым абстракциям Swift Concurrency.

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

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