Всегда ли вызов sync на main очереди приводит к deadlock?

«Всегда ли вызов sync на main очереди приводит к deadlock?» — вопрос из категории Многопоточность, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, не всегда. Deadlock гарантированно произойдет только если sync вызывается на DispatchQueue.main из того же самого MainThread.

Механизм deadlock:

  1. sync блокирует текущий поток до завершения переданного блока.
  2. Если этот вызов делается из MainThread, поток блокируется и ждет.
  3. Поскольку MainQueue последовательная, она не может начать выполнение нового блока (того, который мы передали в sync), пока не завершит текущий (тот, из которого был вызван sync). Возникает взаимная блокировка.

Пример deadlock:

// ВЫЗОВ ИЗ MAIN THREAD -> DEADLOCK
DispatchQueue.main.sync {
    // Этот блок никогда не начнет выполняться
    print("This will never print")
}

Безопасный вызов: Если sync на DispatchQueue.main вызывается из другого потока (например, из background очереди), deadlock не произойдет. Background поток заблокируется, main поток выполнит блок и разблокирует background поток.

Пример безопасного вызова:

DispatchQueue.global().async {
    // Вызов из фонового потока — БЕЗОПАСНО
    DispatchQueue.main.sync {
        // Обновляем UI на MainThread
        self.label.text = "Updated safely"
    }
    // Код продолжит выполнение здесь после завершения блока выше
}

Правило: Никогда не вызывайте DispatchQueue.main.sync из кода, который может выполняться на MainThread.