У меня есть небольшое тестовое приложение, которое выполняет два потока одновременно.Один увеличивает 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 после завершения обоих потоков?
Может кто-нибудь объяснить мне, как lock
/ Monitor.Enter/Exit
обеспечиваетчто процессорные кэши (кэши L1 / L2) синхронизированы?