Sobes.tech
Back to questions
Middle
128
questionbank

Что такое состояние гонки (race condition)?

Sobes Copilot

Get answers in real time

Answer from AI

sobes.tech AI

Состояние гонки возникает, когда два или более потока или процессов одновременно обращаются к общему ресурсу (например, переменной, файлу, базе данных) и результат операции зависит от того, в каком порядке эти потоки/процессы выполнят свои действия. Из-за непредсказуемого порядка доступа и изменения данных, результат может быть некорректным или неожиданным.

Пример в iOS: Предположим, у нас есть счетчик count, к которому одновременно обращаются два потока для инкрементации.

var count = 0

func incrementCount() {
    // Поток 1 считывает count = 5
    // Поток 2 считывает count = 5
    let currentCount = count
    // Поток 1 вычисляeт newCount = 6
    // Поток 2 вычисляeт newCount = 6
    let newCount = currentCount + 1
    // Поток 1 записывает count = 6
    // Поток 2 записывает count = 6 (перезаписывая результат Потока 1)
    count = newCount
}

// Если два потока вызовут incrementCount() одновременно,
// ожидаемый результат будет count = 2,
// но из-за состояния гонки, count может стать равным 1.

Для предотвращения состояний гонки применяются механизмы синхронизации:

  • Lock/Mutex: Блокируют доступ к ресурсу, пока поток его использует.
    import Foundation
    
    let lock = NSLock()
    var count = 0
    
    func incrementCount() {
        lock.lock() // Захватываем блокировку
        let currentCount = count
        let newCount = currentCount + 1
        count = newCount
        lock.unlock() // Освобождаем блокировку
    }
    
  • Очереди (Queues): Использование последовательных очередей GCD.
    import Foundation
    
    let serialQueue = DispatchQueue(label: "com.myapp.counterQueue")
    var count = 0
    
    func incrementCount() {
        serialQueue.async {
            let currentCount = count
            let newCount = currentCount + 1
            count = newCount
        }
    }
    
  • Атомарные операции: Неразрывные операции на уровне инструкций процессора. В Swift можно использовать OSAtomic... (устарело) или Atomic из @_implementationOnly import Atomics (экспериментально), или же подходы на основе блокировок/очередей.

Выбор метода синхронизации зависит от конкретного сценария и требований к производительности. Важно понимать, что синхронизация может вносить дополнительную нагрузку и потенциально приводить к взаимным блокировкам (deadlocks), если реализована некорректно.