Ответ
NSLock — это нерекурсивная блокировка (mutex). Попытка потока, который уже владеет этой блокировкой, захватить её снова приведёт к взаимной блокировке (deadlock) этого потока.
NSRecursiveLock — это рекурсивная блокировка. Она позволяет одному и тому же потоку захватывать её многократно, что необходимо для рекурсивных функций или цепочек методов, использующих общий ресурс.
Практическое правило: Используйте NSRecursiveLock, когда код в защищаемой критической секции может (прямо или косвенно) снова вызвать код, который также пытается захватить ту же самую блокировку.
Пример сценария для NSRecursiveLock:
let recursiveLock = NSRecursiveLock()
var sharedResource = 0
func methodA() {
recursiveLock.lock()
defer { recursiveLock.unlock() }
sharedResource += 1
methodB() // Вызов другого метода, которому тоже нужен этот lock
}
func methodB() {
recursiveLock.lock() // Без NSRecursiveLock здесь был бы deadlock!
defer { recursiveLock.unlock() }
sharedResource *= 2
}
// Вызов
methodA() // Работает корректно с NSRecursiveLock
Сравнение производительности: NSLock обычно легче и немного быстрее, чем NSRecursiveLock, так как ему не нужно отслеживать глубину рекурсии. Поэтому для нерекурсивного кода всегда предпочтительнее NSLock.
Альтернатива в Swift: Рассмотрите использование os_unfair_lock (более производительный, но нерекурсивный) или рекурсивных мьютексов из pthread для сложных сценариев.