В чем разница между состоянием гонки (Race Condition) и гонкой данных (Data Race)?

Ответ

Это два тесно связанных, но разных понятия в конкурентном программировании. Race Condition — это более широкое понятие, чем Data Race.

Race Condition (Состояние гонки)

Это дефект в программе, при котором результат ее работы зависит от непредсказуемой последовательности или времени выполнения событий (например, порядка выполнения горутин). Проблема возникает на уровне логики приложения.

Пример (без гонки данных):
Две горутины выполняют операции, которые должны быть атомарными как единое целое. Одна горутина проверяет условие, а другая его меняет.

var a, b int
var wg sync.WaitGroup
wg.Add(2)

// Горутина 1: Инициализирует данные
go func() {
    defer wg.Done()
    a = 1
    time.Sleep(100 * time.Millisecond) // Имитация работы
    b = 2
}()

// Горутина 2: Проверяет данные
go func() {
    defer wg.Done()
    // Эта проверка может сработать в момент, когда `a` уже равно 1, а `b` еще равно 0
    if b == 2 {
        fmt.Println("a is", a) // Может вывести 0 или 1, в зависимости от планировщика
    }
}()

wg.Wait()

Здесь нет одновременной записи/чтения одной переменной, но логика нарушена из-за порядка выполнения.

Data Race (Гонка данных)

Это конкретный вид ошибки, который возникает, когда:

  1. Две или более горутины одновременно обращаются к одной и той же области памяти.
  2. Хотя бы одно из этих обращений — запись.
  3. Доступ не синхронизирован (нет мьютексов, каналов и т.д.).

Пример:
Классический пример с инкрементом счетчика.

var counter int

// Несколько горутин одновременно читают значение counter, 
// увеличивают его и записывают обратно. Операция не атомарна.
go func() { counter++ }()
go func() { counter++ }()

Итог и обнаружение:

  • Data Race — это проблема на уровне доступа к памяти. Ее можно надежно обнаружить с помощью встроенного детектора: go run -race main.go.
  • Race Condition — это проблема на уровне логики программы. Ее нельзя обнаружить автоматически, она требует внимательного проектирования и использования примитивов синхронизации (мьютексы, каналы, WaitGroup) для обеспечения правильного порядка операций.

Таким образом, data race — это одна из возможных причин race condition, но не единственная.