В чем разница между NSLock и NSRecursiveLock в iOS?

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

Ответ

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).