← Назад к вопросам

Какие знаешь виды lock в iOS?

1.7 Middle🔥 151 комментариев
#Многопоточность и асинхронность

Комментарии (1)

🐱
deepseek-v3.2PrepBro AI5 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Виды lock в iOS

В iOS, как и в общем случае в параллельном программировании, lock (блокировка) — это механизм синхронизации, который предотвращает одновременный доступ нескольких потоков к общему ресурсу, обеспечивая потокобезопасность (thread safety). Виды lock различаются по поведению, производительности и сценариям использования. В iOS применяются как классические блокировки из низкоуровневого C/Objective-C API, так и современные механизмы Swift.

Основные виды блокировок

1. POSIX Mutex (pthread_mutex_t)

Базовый мьютекс из стандарта POSIX, доступный через библиотеку pthread. Предоставляет низкоуровневый контроль.

#include <pthread.h>
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_lock(&mutex);
// Критическая секция
pthread_mutex_unlock(&mutex);
  • Особенности: Легковесный, может быть настраиваемым (например, рекурсивным через PTHREAD_MUTEX_RECURSIVE).
  • Использование: В Objective-C или C-коде, где нужна максимальная производительность.

2. NSLock и его варианты

Классы блокировок из Foundation, Objective-C API, также доступны в Swift через bridging.

  • NSLock: Стандартная блокировка, некогда захваченная, блокирует другие потоки до разблокировки.
let lock = NSLock()
lock.lock()
// Критическая секция
lock.unlock()
  • NSRecursiveLock: Рекурсивная блокировка, позволяет одному потоку захватывать её многократно (например, в рекурсивных вызовах), что предотвращает взаимную блокировку (deadlock) в таких сценариях.
let recursiveLock = NSRecursiveLock()
func recursiveMethod(_ value: Int) {
    recursiveLock.lock()
    defer { recursiveLock.unlock() }
    if value > 0 {
        recursiveMethod(value - 1)
    }
}
  • NSCondition и NSConditionLock: Блокировки с условиями (condition variables), позволяют потокам ждать определённого состояния.
    - **NSCondition**: Комбинирует мьютекс и условие, используется для ожидания и сигнализации.
```swift
let condition = NSCondition()
var available = false
// Поток 1 (ожидание)
condition.lock()
while !available {
    condition.wait()
}
condition.unlock()
// Поток 2 (сигнал)
condition.lock()
available = true
condition.signal()
condition.unlock()
```
    - **NSConditionLock**: Более высокоуровневая реализация, блокируется на основе конкретного целочисленного условия.

3. POSIX Read-Write Lock (pthread_rwlock_t)

Блокировка чтения-записи, оптимизирована для сценариев, где много операций чтения и редкие записи. Позволяет нескольким потокам одновременно читать, но захватывается исключительно для записи.

pthread_rwlock_t rwlock = PTHREAD_RWLOCK_INITIALIZER;
pthread_rwlock_rdlock(&rwlock); // Захват для чтения
pthread_rwlock_wrlock(&rwlock); // Захват для записи
pthread_rwlock_unlock(&rwlock);
  • Особенности: Повышает производительность в read-heavy сценариях.
  • Использование: Кэши, структуры данных с частым чтением.

4. Unfair Lock (os_unfair_lock)

Нечестная блокировка, представленная в iOS 10+ через <os/lock.h>. Замена устаревшему OSSpinLock, который был небезопасен из-за проблемы priority inversion (инверсии приоритетов) на QoS.

#include <os/lock.h>
os_unfair_lock unfairLock = OS_UNFAIR_LOCK_INIT;
os_unfair_lock_lock(&unfairLock);
// Критическая секция
os_unfair_lock_unlock(&unfairLock);
  • Особенности: Легковесный, высокопроизводительный, но «нечестный» — не гарантирует порядок получения блокировки ждущими потоками. Требует осторожности во избежание голодания (starvation) низкоприоритетных потоков.
  • Важно: Доступен в Swift как os_unfair_lock, но требует ручного управления памятью (не является объектом Swift).

5. Synchronized (директива @synchronized)

Директива Objective-C, устаревший, но всё ещё встречающийся подход. Синтаксический сахар для рекурсивного мьютекса.

@synchronized(self) {
    // Критическая секция
}
  • Особенности: Удобный, но относительно медленный (добавляет обработку исключений), не подходит для Swift. Не рекомендуется к использованию в новом коде.

6. GCD Serial Queue (последовательная очередь)

Подход на основе Grand Central Dispatch, где последовательная очередь (serial queue) исполняет задачи по одной, что обеспечивает потокобезопасность без явных блокировок. Часто считается лучшей практикой в Swift.

let serialQueue = DispatchQueue(label: "com.example.serialQueue")
serialQueue.async {
    // Критическая секция: гарантировано выполнение в одном потоке
}
  • Особенности: Использует GCD для управления потоками, обычно более производителен и безопасен, чем явные блокировки.
  • Вариант с барьером (barrier): Для read-write сценариев используется concurrent queue с barrier для записи.
let concurrentQueue = DispatchQueue(label: "com.example.concurrentQueue", attributes: .concurrent)
concurrentQueue.async(flags: .barrier) {
    // Запись: эксклюзивный доступ
}

7. Actor (в Swift с версии 5.5)

Современный механизм языка Swift, встроенная поддержка изоляции состояния. Actor обеспечивает потокобезопасность на уровне компилятора.

actor Counter {
    private var value = 0
    func increment() {
        value += 1
    }
}
let counter = Counter()
Task {
    await counter.increment() // await гарантирует изолированный доступ
}
  • Особенности: Самый высокоуровневый и безопасный способ, компилятор контролирует доступ к состоянию. Не является блокировкой в классическом смысле, но решает те же задачи.

Сравнение и рекомендации

  • Производительность: os_unfair_lock и pthread_mutex_t — самые быстрые. @synchronized — самый медленный.
  • Безопасность: Actor и GCD serial queue предпочтительны в Swift, так как уменьшают риск deadlock и race conditions.
  • Сценарии:
    - Для защиты простых критических секций: `NSLock` или `os_unfair_lock`.
    - Для read-heavy структур: **read-write lock** или **GCD с barrier**.
    - Для рекурсивных вызовов: `NSRecursiveLock`.
    - Для координации потоков по условиям: `NSCondition`.
    - В современном Swift-коде: **Actor** или **serial queue**.

Важно выбирать lock соответственно задаче, учитывая производительность, безопасность и читаемость кода. Неправильное использование блокировок может привести к deadlock'ам, голоданию потоков или инверсии приоритетов, особенно на платформе iOS с её разнородными QoS.