Что произойдёт при одновременном обращении двух потоков к одной переменной в C++ без синхронизации?

«Что произойдёт при одновременном обращении двух потоков к одной переменной в C++ без синхронизации?» — вопрос из категории Многопоточность, который задают на 25% собеседований C/C++ Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Такая ситуация называется состоянием гонки (Data Race) и является неопределённым поведением (Undefined Behavior) согласно стандарту C++. Программа может вести себя непредсказуемо.

Возможные последствия:

  1. Повреждение данных: Результат операции может быть некорректным.
  2. Критические сбои: Повреждение структур данных кучи (heap corruption), ведущее к падению программы.
  3. Несогласованное состояние: Разные потоки увидят разные значения переменной.
  4. Проблемы с оптимизацией: Компилятор вправе переупорядочивать операции с памятью в отсутствие синхронизации, что может привести к контринтуитивным результатам.

Пример гонки данных:

#include <iostream>
#include <thread>
#include <vector>

int shared_counter = 0; // Разделяемая переменная

void increment() {
    for (int i = 0; i < 100000; ++i) {
        ++shared_counter; // НЕАТОМАРНАЯ операция: чтение-изменение-запись
    }
}

int main() {
    std::thread t1(increment);
    std::thread t2(increment);

    t1.join();
    t2.join();

    // Результат почти гарантированно будет меньше 200000
    std::cout << "Final counter value: " << shared_counter << std::endl;
    return 0;
}

Способы обеспечить безопасный доступ:

  • Мьютексы (std::mutex, std::shared_mutex): Гарантируют эксклюзивный доступ.
  • Атомарные операции (std::atomic<T>): Для простых типов данных. В примере выше нужно было использовать std::atomic<int> shared_counter{0};.
  • Lock-free структуры данных: Для высокопроизводительных сценариев.
  • Локальная память потока (thread_local): Если данные не нужно разделять.

Правило: Любой доступ (чтение или запись) к неатомарному объекту, который может быть изменён из другого потока, должен быть защищён механизмом синхронизации.