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

Что такое критическая секция?

1.3 Junior🔥 22 комментариев
#Многопоточность и асинхронность

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

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

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

Что такое критическая секция в контексте iOS-разработки?

Критическая секция — это участок кода (фрагмент программы), который одновременно может выполняться только одним потоком (thread) в многопоточной среде. Если несколько потоков попытаются войти в критическую секцию одновременно, это приведёт к состоянию гонки (race condition), нарушению целостности данных и непредсказуемому поведению приложения. В iOS-разработке работа с критическими секциями — фундаментальный аспект создания стабильных и отзывчивых приложений.

Почему это важно в iOS?

Многопоточность в iOS повсеместна: обновление UI в основном потоке, фоновая загрузка данных, работа с Core Data, операции с файловой системой, сетевые запросы. Общие ресурсы (shared resources), такие как:

  • Изменяемые объекты (например, элементы массива NSMutableArray).
  • Свойства класса (особенно var в Swift).
  • Файлы.
  • Статические переменные.
  • Экземпляры синглтонов. – требуют защиты при доступе из нескольких потоков.

Пример опасности без критической секции:

Представьте, что два потока одновременно пытаются добавить объекты в один массив:

// НЕПРАВИЛЬНО: Общий ресурс без защиты
var sharedArray = [Int]()

DispatchQueue.global().async {
    for i in 0..<100 {
        sharedArray.append(i) // Поток 1
    }
}

DispatchQueue.global().async {
    for i in 100..<200 {
        sharedArray.append(i) // Поток 2
    }
}
// Результат: массив может быть повреждён, часть данных потеряется, приложение может крашнуться.

Механизмы реализации (синхронизации) в iOS/Swift

Для защиты критических секций используются примитивы синхронизации. Наиболее распространённые в iOS:

  1. Серийные очереди (Serial DispatchQueue) — предпочтительный идиоматичный способ в Swift.

    let serialQueue = DispatchQueue(label: "com.example.serialQueue")
    var sharedArray = [Int]()
    
    func addToArray(_ value: Int) {
        serialQueue.async { // Задачи выполняются строго по очереди
            sharedArray.append(value)
        }
    }
    // Или синхронно, если нужно дождаться результата:
    func safeGetArray() -> [Int] {
        return serialQueue.sync {
            return sharedArray
        }
    }
    
  2. Мьютексы (Mutex) — низкоуровневый примитив. NSLock и pthread_mutex_t являются мьютексами.

    let lock = NSLock()
    var counter = 0
    
    func incrementCounter() {
        lock.lock()
        defer { lock.unlock() } // Гарантирует разблокировку при выходе из области видимости
        counter += 1
    }
    
  3. Рекурсивные мьютексы (NSRecursiveLock) — позволяют одному потоку захватывать замок несколько раз, что полезно в рекурсивных функциях.

  4. Семафоры (DispatchSemaphore) — позволяют ограничить количество потоков, одновременно входящих в секцию (не только одним).

    let semaphore = DispatchSemaphore(value: 1) // Разрешает одновременный доступ 1 потоку
    
    semaphore.wait() // Уменьшает счётчик (захват)
    // Критическая секция
    semaphore.signal() // Увеличивает счётчик (освобождение)
    
  5. Акторы (Actors) — новая модель на уровне языка, представленная в Swift 5.5. Актор изолирует своё состояние и гарантирует, что к его изменяемым свойствам имеет доступ только одна задача в момент времени.

    actor CounterActor {
        private var value = 0
    
        func increment() {
            value += 1
        }
    
        func getValue() -> Int {
            return value
        }
    }
    
    // Использование
    let counter = CounterActor()
    Task {
        await counter.increment() // `await` указывает на потенциальную приостановку для безопасного доступа
    }
    

Ключевые принципы работы с критическими секциями

  • Минимизация времени нахождения в секции: Критическую секцию нужно делать максимально короткой, чтобы не блокировать другие потоки без необходимости, что напрямую влияет на производительность и отзывчивость UI.
  • Избегание взаимной блокировки (deadlock): Ситуация, когда два или более потока бесконечно ждут друг друга, освободив захваченные ресурсы. Часто возникает при использовании нескольких замков в неправильном порядке.
  • Выбор правильного инструмента: Для большинства задач высокого уровня в Swift предпочтительны серийные очереди или акторы. Низкоуровневые NSLock или семафоры используются для более специфичных сценариев.

Вывод: Понимание и корректное применение механизмов синхронизации для защиты критических секций — обязательный навык iOS-разработчика. Это обеспечивает потокобезопасность (thread safety), предотвращает трудноуловимые гонки данных и краши приложения, что критически важно для создания качественного, надёжного и конкурентноспособного программного обеспечения. Игнорирование этих принципов ведёт к нестабильной работе приложения, которое будет непредсказуемо падать у пользователей, особенно на многоядерных устройствах.

Что такое критическая секция? | PrepBro