Что такое Data Race и как привести пример?

ошибка конкурентного доступа к памяти два или несколько потоков читают и изменяют общий ресурс, не используя синхронизацию это вызывает ошибки и непредсказуемое поведение, например появление некорректных данных…

Короткий ответ

Что ответить на собеседовании

ошибка конкурентного доступа к памяти два или несколько потоков читают и изменяют общий ресурс, не используя синхронизацию это вызывает ошибки и непредсказуемое поведение, например появление некорректных данных причина — отсутствие блокировок либо атомарных операций например, два потока одновременно инкрементируют один счётчик без мьютекса результатом становятся нестабильность программы и сложная отладка проблему устраняют с помощью мьютексов, атомарных операций или других средств синхронизации

Подробный разбор

Ответ с пояснениями

Что называют Data Race?

  • ошибка конкурентного доступа к памяти
  • два или несколько потоков читают и изменяют общий ресурс, не используя синхронизацию
  • это вызывает ошибки и непредсказуемое поведение, например появление некорректных данных
  • причина — отсутствие блокировок либо атомарных операций
  • например, два потока одновременно инкрементируют один счётчик без мьютекса
  • результатом становятся нестабильность программы и сложная отладка
  • проблему устраняют с помощью мьютексов, атомарных операций или других средств синхронизации

Пример:

var counter int

func increment() {
counter++  // неатомарно
}

// два потока вызывают increment() без блокировок

Здесь возможен Data Race, поскольку операция ++ не является атомарной: чтение, увеличение и запись значения могут выполняться вперемешку.

Подробный ответ

Основной ответ

Data race — это ситуация в многопоточной программе, при которой два или более потока одновременно обращаются к одной области памяти без корректной синхронизации, причём хотя бы один из них выполняет запись. Это приводит к неопределённому поведению: программа может работать нестабильно или возвращать неправильные данные. Data race нередко становится источником труднообнаруживаемых ошибок, поскольку проявляется только при определённом порядке выполнения потоков.

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

  • Отсутствие синхронизации: чтобы предотвратить data race, применяют блокировки (mutex, semaphore) либо атомарные операции.
  • Непредсказуемость: ошибка возникает не при каждом запуске, поэтому её особенно трудно выявить. Даже внешне корректный результат не означает, что data race отсутствует.
  • Различие с deadlock: data race представляет собой конфликт при обращении к данным, тогда как deadlock — взаимную блокировку потоков, из-за которой выполнение останавливается.

Пример

Рассмотрим ситуацию, в которой два потока без синхронизации одновременно увеличивают общий счётчик:

int counter = 0;

void increment() {
counter = counter + 1;
}

Если два потока одновременно выполнят increment(), операции чтения и записи значения counter могут пересечься. Поэтому результатом окажется не 2, а 1: один инкремент будет потерян. Для исправления операцию следует защитить мьютексом или применить атомарный тип, например std::atomic<int> в C++11 и более новых версиях.

Практический контекст

В современных многопоточных приложениях, включая Java concurrency и C++ с threading, предотвращение data race является важной задачей. Во время тестирования обнаружить такие ошибки помогают инструменты ThreadSanitizer и Helgrind. В Java применяются volatile и synchronized, а в C++ — std::mutex и атомарные операции, обеспечивающие безопасный доступ к данным.

Практика в реальном времени

Подготовьтесь к следующему собеседованию

Interview Boost учитывает вакансию, резюме и технологии и помогает сформулировать ответ прямо во время интервью.

Начать подготовку