У меня есть небольшое тестовое приложение, которое одновременно выполняет два потока. Один увеличивает 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)?