Как и многие другие люди, меня всегда путают волатильные чтения/записи и заборы. Итак, теперь я пытаюсь полностью понять, что они делают.
Таким образом, волатильное чтение должно (1) демонстрировать семантику получения и (2) гарантировать, что прочитанное значение является свежим, то есть оно не является кешированным значением. Пусть сосредоточиться на (2).
Теперь, я прочитал, что, если вы хотите выполнить изменчивое чтение, вам следует ввести забор (или полный забор) после чтения, например:
int local = shared;
Thread.MemoryBarrier();
Как именно это мешает операции чтения использовать ранее кэшированное значение? В соответствии с определением ограждения (никакие чтения/магазины не могут быть перемещены выше/ниже забора), я бы вставлял забор перед чтением, не позволяя чтению переходить через забор и перемещаться назад во времени (ака, будучи кэшируется).
Как предотвращение перемотки чтения вовремя (или последующие инструкции от перемещения назад во времени) гарантируют неизменное (новое) чтение? Как это помогает?
Точно так же я считаю, что волатильная запись должна вводить забор после операции записи, не позволяя процессору перемещать запись вперед во времени (иначе, задерживая запись). Я считаю, что это приведет к тому, что процессор запустит запись в основную память.
Но, к моему удивлению, реализация С# представляет забор перед записью!
[MethodImplAttribute(MethodImplOptions.NoInlining)] // disable optimizations
public static void VolatileWrite(ref int address, int value)
{
MemoryBarrier(); // Call MemoryBarrier to ensure the proper semantic in a portable way.
address = value;
}
Обновление
В соответствии с этим примером, по-видимому, взятым из "С# 4 в двух словах", забор 2, помещенный после того, как запись, как предполагается, заставит запись стираться основная память немедленно, а забор 3, помещенный перед чтением, должен гарантировать свежее чтение:
class Foo{
int _answer;
bool complete;
void A(){
_answer = 123;
Thread.MemoryBarrier(); // Barrier 1
_complete = true;
Thread.MemoryBarrier(); // Barrier 2
}
void B(){
Thread.MemoryBarrier(); // Barrier 3;
if(_complete){
Thread.MemoryBarrier(); // Barrier 4;
Console.WriteLine(_answer);
}
}
}
Идеи в этой книге (и мои собственные личные убеждения), кажется, противоречат идеям реализаций С# VolatileRead
и VolatileWrite
.