Вопрос проверяет понимание низкоуровневых проблем параллелизма, связанных с неконтролируемым доступом к памяти.
Data Race (гонка данных) возникает, когда два или более потока обращаются к одной и той же области памяти без надлежащей синхронизации, и хотя бы один из этих потоков выполняет запись. Результат выполнения программы становится непредсказуемым и зависит от случайного порядка выполнения потоков. Это низкоуровневая ошибка параллелизма.
Data Race — это ситуация неопределенного поведения программы из-за неконтролируемого доступа к общим данным.
Условия возникновения Data Race:
Как минимум два потока обращаются к одной переменной.
Как минимум один поток изменяет (пишет) эту переменную.
Нет механизма синхронизации (например, synchronized, мьютекса), который бы гарантировал порядок доступа.
Пример на Java:
Рассмотрим простой счетчик, который увеличивается из нескольких потоков.
public class DataRaceExample {
private static int counter = 0;
public static void main(String[] args) throws InterruptedException {
Thread thread1 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
counter++; // Не атомарная операция: чтение -> изменение -> запись
}
});
Thread thread2 = new Thread(() -> {
for (int i = 0; i < 100000; i++) {
counter++;
}
});
thread1.start();
thread2.start();
thread1.join();
thread2.join();
System.out.println("Counter value: " + counter); // Результат меньше 200000
}
}Почему результат не равен 200000?
Операция counter++ не является атомарной. Она состоит из трех шагов:
Прочитать текущее значение counter в регистр процессора.
Увеличить значение в регистре на 1.
Записать новое значение обратно в память.
Потоки могут выполнять эти шаги вперемешку. Например, оба потока прочитают значение 5, увеличат его до 6 каждый и запишут 6. В результате два увеличения дадут +1 вместо +2.
Вывод: Data Race приводит к тихим ошибкам (без исключений), которые сложно обнаружить. Для предотвращения необходимо использовать синхронизацию.