Ответ
NSLock — это нерекурсивный мьютекс. Если поток, уже владеющий блокировкой, попытается захватить её снова, это приведёт к взаимной блокировке (deadlock).
NSRecursiveLock — это рекурсивный мьютекс. Он позволяет одному и тому же потоку захватывать блокировку несколько раз без deadlock, что необходимо для рекурсивных функций или методов, которые косвенно вызывают сами себя.
Пример, демонстрирующий разницу:
// NSLock — приведёт к deadlock
let lock = NSLock()
lock.lock()
// Вызов внутри критической секции, требующий той же блокировки:
lock.lock() // DEADLOCK — поток заблокирует сам себя
lock.unlock()
// NSRecursiveLock — работает корректно
let recursiveLock = NSRecursiveLock()
func recursiveTask(count: Int) {
recursiveLock.lock()
defer { recursiveLock.unlock() }
if count > 0 {
// Рекурсивный вызов безопасен
recursiveTask(count: count - 1)
}
}
recursiveTask(count: 5)
Когда использовать:
- NSLock: Для обычной синхронизации нерекурсивного кода. Он легче и быстрее.
- NSRecursiveLock: Когда логика потока может потребовать многократного захвата одной блокировки (рекурсия, вызов нескольких методов, использующих общий lock).