Ответ
Для возникновения deadlock достаточно двух потоков.
Условия взаимной блокировки (Coffman conditions):
- Взаимное исключение: Потоки удерживают монопольный доступ к ресурсам (например, через
NSLock). - Удержание и ожидание: Поток, удерживая один ресурс, пытается получить доступ к другому.
- Отсутствие вытеснения: Ресурс нельзя отнять у потока, только добровольно освободить.
- Циклическое ожидание: Потоки образуют кольцо, где каждый ждет ресурс, удерживаемый следующим.
Пример deadlock на Swift с двумя потоками:
let lockA = NSLock()
let lockB = NSLock()
DispatchQueue.global().async {
lockA.lock()
sleep(1) // Имитация работы с ресурсом A
// Поток 1 ждет, пока освободится lockB
lockB.lock() // БЛОКИРОВКА: lockB удерживается потоком 2
// Критическая секция...
lockB.unlock()
lockA.unlock()
}
DispatchQueue.global().async {
lockB.lock()
sleep(1) // Имитация работы с ресурсом B
// Поток 2 ждет, пока освободится lockA
lockA.lock() // БЛОКИРОВКА: lockA удерживается потоком 1
// Критическая секция...
lockA.unlock()
lockB.unlock()
}
// Оба потока заблокированы навсегда.
Как избежать: устанавливать строгий порядок захвата блокировок или использовать методы вроде NSLock.try().