Приведи пример DeadLock
Комментарии (2)
Ответ сгенерирован нейросетью и может содержать ошибки
Пример DeadLock в iOS/multithreading контексте
Deadlock (взаимная блокировка) — ситуация в многопоточной системе, когда два или более потока бесконечно ожидают друг друга, потому что каждый держит ресурс, необходимый другому, и не отпускает его до получения своего требуемого ресурса. Это классическая проблема синхронизации.
Ключевые условия возникновения Deadlock
- Mutual Exclusion (взаимное исключение): ресурс нельзя использовать одновременно несколькими потоками.
- Hold and Wait (захват и ожидание): поток держит один ресурс и ждет другой.
- No Preemption (неотъемлемость): ресурс нельзя强制но отнять у потока.
- Circular Wait (циклическое ожидание): потоки образуют цикл ожидания.
Практический пример в Swift с использованием DispatchQueue и sync
Рассмотрим классический пример с двумя потоками и двумя разделяемыми ресурсами (в данном случае — очередь DispatchQueue).
import Foundation
let queueA = DispatchQueue(label: "com.example.queueA")
let queueB = DispatchQueue(label: "com.example.queueB")
var resourceA = 0
var resourceB = 0
// В потоке queueA пытаемся получить доступ к resourceB через queueB
queueA.async {
print("Поток A начинает работу, блокирует resourceA")
queueA.sync { // Первый захват: queueA блокирует себя для синхронного выполнения
resourceA += 1
print("Поток A: resourceA = \(resourceA)")
}
print("Поток A пытается получить resourceB через queueB")
// СИНХРОННЫЙ вызов на queueB -> потенциальный deadlock
queueB.sync {
resourceB += 1
print("Поток A: resourceB = \(resourceB)")
}
}
// В потоке queueB пытаемся получить доступ к resourceA через queueA
queueB.async {
print("Поток B начинает работу, блокирует resourceB")
queueB.sync {
resourceB += 1
print("Поток B: resourceB = \(resourceB)")
}
print("Поток B пытается получить resourceA через queueA")
// СИНХРОННЫЙ вызов на queueA -> deadlock
queueA.sync {
resourceA += 1
print("Поток B: resourceA = \(resourceA)")
}
}
// Даем время на выполнение
sleep(2)
print("Программа завершилась? Возможно, deadlock!")
Как это работает и почему deadlock:
- Поток A (на
queueA) захватывает свою очередь черезqueueA.sync(это уже блокирует очередь для других синхронных задач). - Затем он пытается выполнить синхронную (
queueB.sync) операцию на очереди B. - Поток B (на
queueB) одновременно захватывает свою очередь черезqueueB.sync. - Затем он пытается выполнить синхронную (
queueA.sync) операцию на очереди A. - Возникает циклическая зависимость:
queueAждет, покаqueueBосвободится (для своегоqueueB.sync).queueBждет, покаqueueAосвободится (для своегоqueueA.sync).
- Обе очереди заблокированы для синхронных операций, и ни одна не может продолжить — deadlock.
Более простой и частый пример в iOS
// Deadlock на главной очереди (Main DispatchQueue)
DispatchQueue.main.async {
print("Это выполнится")
// Синхронный вызов на той же очереди, которая уже выполняет этот блок — deadlock!
DispatchQueue.main.sync {
print("Это никогда не выполнится")
}
}
Почему это deadlock: Поток главной очереди уже выполняет блок .async. Вызов .sync требует немедленного выполнения задачи на этой же очереди, но очередь не может обрабатывать новую задачу, пока не завершит текущую. Получается бесконечное ожидание самого себя.
Как избегать Deadlock в iOS разработке
- Избегайте
syncна той же очереди, особенно на Main Queue. - Используйте асинхронные вызовы (
async) вместо синхронных, когда возможны циклические зависимости. - При работе с несколькими ресурсами устанавливайте глобальный порядок захвата (например, всегда сначала захватывать ресурс A, затем ресурс B).
- Используйте высокоуровневые механизмы: OperationQueue с зависимостями, actors в Swift 5.5+.
- Для сложных сценариев применяйте технику "try lock" (например, через
os_unfair_lock_trylock) или timeouts.
Deadlock — одна из самых сложных проблем для диагностики, потому что система просто "замирает" без явных ошибок. В iOS особенно опасно делать sync на Main Queue из background queue — это гарантированный deadlock, если главная очередь занята (например, ожидает ответа от этого background task).