Ответ
Для безопасного доступа к общим ресурсам из нескольких потоков в iOS используется ряд примитивов.
Основные примитивы (от простых к сложным):
-
NSLock/os_unfair_lock- Простая взаимная блокировка (mutex).
NSLock— высокоуровневый,os_unfair_lock— низкоуровневый и более эффективный.let lock = NSLock() var sharedValue = 0
func increment() { lock.lock() defer { lock.unlock() } // Гарантирует разблокировку sharedValue += 1 }
- Простая взаимная блокировка (mutex).
-
DispatchSemaphore- Ограничивает количество потоков, одновременно имеющих доступ к ресурсу (часто значение = 1 для мьютекса).
let semaphore = DispatchSemaphore(value: 1) semaphore.wait() // Уменьшает счетчик // Критическая секция semaphore.signal() // Увеличивает счетчик
- Ограничивает количество потоков, одновременно имеющих доступ к ресурсу (часто значение = 1 для мьютекса).
-
DispatchQueueс барьером (Barrier)- Идеально для чтения/записи. Позволяет множественное чтение, но запись происходит эксклюзивно.
let concurrentQueue = DispatchQueue(label: "com.queue", attributes: .concurrent) var internalArray = [Int]()
func write(_ value: Int) { concurrentQueue.async(flags: .barrier) { internalArray.append(value) // Эксклюзивная запись } } func read() -> [Int] { concurrentQueue.sync { // Одновременное чтение return internalArray } }
- Идеально для чтения/записи. Позволяет множественное чтение, но запись происходит эксклюзивно.
-
NSRecursiveLock- Разновидность
NSLock, которую один поток может захватывать несколько раз. Нужен для рекурсивных функций.
- Разновидность
-
Actor (Swift 5.5+)
- Современный, безопасный подход. Компилятор гарантирует изоляцию: доступ к свойствам актора возможен только асинхронно.
actor Counter { private var value = 0 func increment() { value += 1 } func getValue() -> Int { value } } // Использование: let counter = Counter() Task { await counter.increment() let currentValue = await counter.getValue() }
- Современный, безопасный подход. Компилятор гарантирует изоляцию: доступ к свойствам актора возможен только асинхронно.
Рекомендации по выбору:
- Для простых критических секций:
NSLockилиos_unfair_lock. - Для паттерна читатель-писатель:
DispatchQueueс барьером. - Для нового кода (Swift Concurrency): Используйте
actor. - Избегайте устаревших
@synchronized(Objective-C) иOSAtomicопераций.