Как оператор блокировки обеспечивает синхронизацию внутри процессора?

У меня есть небольшое тестовое приложение, которое одновременно выполняет два потока. Один увеличивает static long _value , другой уменьшает его. С помощью ProcessThread.ProcessorAffinity я заверил, что потоки связаны с разными физическими (без HT) ядрами для обеспечения внутрипроцессорной связи, и я убедился, что они перекрываются во времени выполнения в течение значительного периода времени.

Конечно, следующее не приводит к нулю:

for (long i = 0; i < 10000000; i++)
{
    _value += offset;
}

Итак, логический вывод будет:

for (long i = 0; i < 10000000; i++)
{
    Interlocked.Add(ref _value, offset);
}

Что, конечно, ведет к нулю.

Однако следующее также приводит к нулю:

for (long i = 0; i < 10000000; i++)
{
    lock (_syncRoot)
    {
        _value += offset;
    }
}

Конечно, Оператор lock гарантирует, что операции чтения и записи не переупорядочиваются, потому что он использует полное ограждение. Однако я не могу найти никакой информации о синхронизации кешей процессора. Если бы не было никакой синхронизации кеша, я бы подумал, что я должен видеть отклонение от 0 после завершения обоих потоков?

Может кто-нибудь объяснить мне, как блокирует / Monitor.Enter / Exit обеспечивает синхронизацию кэшей процессора (кэшей L1 / L2)?

10
задан Pieter van Ginkel 13 May 2011 в 19:12
поделиться