Кажется, что примитивы атомарны. Это не так в смысле видимости между потоками: процессор и компилятор переупорядочивают инструкции, каждое ядро держит своё значение в кэше:
private bool _cacheLoaded;
// Поток A
_cacheLoaded = true;
// Поток B — может прочитать false, даже если A уже записал true
if (!_cacheLoaded) LoadCache(); // загружается дважды, данные затираются
Как это исправить
1.
lock. Подходит для составных операций: «прочитать → изменить → записать» должны выполняться как одно целое:private readonly object _sync = new object();
private int _count;
public void Increment()
{
lock (_sync) { _count++; }
}
2.
volatile. Запрещает кэширование значения в регистре. Не заменяет lock. Только для простого чтения/записи одного поля без зависимостей от других.private volatile bool _cacheLoaded;
3.
Interlocked. Атомарная операция на уровне процессора. Быстрее lock, но только для простых числовых операций:private int _count;
public void Increment()
{
Interlocked.Increment(ref _count);
}
📍 Навигация: Вакансии • Задачи • Собесы
🐸 Библиотека шарписта
#sharp_view