Как реализовать атомарную операцию с использованием GCD в Swift?

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

Ответ

В Swift с помощью Grand Central Dispatch (GCD) атомарность достигается через серийные очереди или барьеры в конкурентных очередях. Оба подхода гарантируют, что критическая секция выполняется без гонки данных.

1. Использование серийной очереди (проще, но менее гибко)

private let serialQueue = DispatchQueue(label: "com.example.atomic.serial")
private var sharedResource: Int = 0

func updateResource(_ newValue: Int) {
    serialQueue.async {
        self.sharedResource = newValue
    }
}

func readResource() -> Int {
    return serialQueue.sync {
        return self.sharedResource
    }
}

2. Использование барьеров в конкурентной очереди (высокая производительность при чтении)

private let concurrentQueue = DispatchQueue(label: "com.example.atomic.concurrent", attributes: .concurrent)
private var sharedResource: Int = 0

func updateResource(_ newValue: Int) {
    // Барьер гарантирует эксклюзивный доступ на запись
    concurrentQueue.async(flags: .barrier) {
        self.sharedResource = newValue
    }
}

func readResource() -> Int {
    // Множественные чтения могут выполняться параллельно
    return concurrentQueue.sync {
        return self.sharedResource
    }
}

Ключевые моменты:

  • Барьеры (flags: .barrier) блокируют очередь на время выполнения задачи, обеспечивая атомарность записи.
  • Серийная очередь выполняет задачи строго последовательно, что также обеспечивает атомарность.
  • Для сложных структур данных или Swift 5.5+ рассмотрите использование акторов (actors) как более современной альтернативы.