Является ли управляемая куча (heap) в .NET потокобезопасной?

«Является ли управляемая куча (heap) в .NET потокобезопасной?» — вопрос из категории Многопоточность, который задают на 25% собеседований C# Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, управляемая куча (managed heap) как механизм выделения памяти не обеспечивает автоматической потокобезопасности для операций с данными, которые в ней хранятся.

  • Выделение памяти: Сам аллокатор кучи в CLR внутренне синхронизирован, поэтому выделение памяти для нового объекта (new MyClass()) из нескольких потоков безопасно.
  • Доступ к данным: Потокобезопасность относится не к куче, а к общим данным (объектам), размещённым в ней. Если несколько потоков обращаются к одному и тому же объекту без координации, возникает состояние гонки.

Пример проблемы и решения:

// НЕПРАВИЛЬНО: Общий список без синхронизации
List<int> sharedList = new List<int>(); // Объект в куче

// Параллельные вызовы из разных потоков приведут к ошибкам
Parallel.For(0, 1000, i =>
{
    sharedList.Add(i); // Возможны исключения или потеря данных
});

// ПРАВИЛЬНО 1: Синхронизация с lock
private List<int> _sharedList = new List<int>();
private readonly object _locker = new object();

Parallel.For(0, 1000, i =>
{
    lock (_locker)
    {
        _sharedList.Add(i); // Теперь безопасно
    }
});

// ПРАВИЛЬНО 2: Использование потокобезопасной коллекции
using System.Collections.Concurrent;
ConcurrentBag<int> threadSafeBag = new ConcurrentBag<int>();

Parallel.For(0, 1000, i =>
{
    threadSafeBag.Add(i); // Внутренняя синхронизация
});

Вывод: Ответственность за синхронизацию доступа к общим объектам в куче лежит на разработчике. Для этого используются примитивы синхронизации (lock, Monitor, SemaphoreSlim, Mutex) или специальные потокобезопасные коллекции.