В каких случаях применяется барьерная операция (dispatch barrier) в GCD?

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

Ответ

Барьерная операция (dispatch_barrier_async) используется в конкурентной очереди для создания точки синхронизации, обеспечивая атомарность записи при параллельных чтениях (шаблон "чтение-запись").

Принцип работы: Все задачи, добавленные в очередь до барьера, выполняются параллельно. Барьерная задача выполняется только одна и монопольно — очередь приостанавливает запуск новых задач до её завершения. Задачи после барьера снова выполняются параллельно.

Пример использования для thread-safe контейнера:

class ThreadSafeContainer<T> {
    private var storage = [T]()
    private let queue = DispatchQueue(label: "com.example.container", attributes: .concurrent)

    func read() -> [T] {
        return queue.sync { // Множество параллельных чтений
            return storage
        }
    }

    func write(_ element: T) {
        queue.async(flags: .barrier) { // Одна эксклюзивная запись
            self.storage.append(element)
        }
    }
}

Типичные сценарии:

  • Кэширование данных (NSCache).
  • Работа с внутренними структурами данных, требующими безопасного доступа из многих потоков.
  • Инициализация или обновление общих ресурсов (конфигурация, файлы).

Важно: Барьеры работают только с очередями, созданными с атрибутом .concurrent. На серийных очередях они не имеют особого эффекта.