В C # 4 in a Nutshell (кстати, настоятельно рекомендуется) используется следующий код для демонстрации концепции MemoryBarrier (при условии, что A и B выполнялись в разных потоках):
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);
}
}
}
они упоминают, что барьеры 1 и 4 не позволяют этому примеру записать 0, а барьеры 2 и 3 обеспечивают гарантию свежести: они гарантируют, что если B выполняется после A, чтение _complete будет оценивать на true.
Я не совсем понимаю. Думаю, я понимаю, почему необходимы барьеры 1 и 4: мы не хотим, чтобы запись в _answer была оптимизирована и размещена после записи в _complete (барьер 1) и нам нужно убедиться, что _answer не кэшируется (Барьер 4). Я также думаю, что понимаю, почему необходим барьер 3: если A работал сразу после записи _complete = true, B все равно нужно было бы обновить _complete, чтобы прочитать правильное значение.
Но я не понимаю, зачем нам Barrier 2! Часть меня говорит, что это потому, что, возможно, поток 2 (запущенный B) уже выполнялся до (но не включая) if (_complete), и поэтому нам нужно убедиться, что _complete обновляется .
Однако я не понимаю, как это помогает. Возможно ли, что для _complete будет установлено значение true в A, но все же метод B увидит кешированную (ложную) версию _complete? То есть, если поток 2 запускал метод B до первого MemoryBarrier, а затем поток 1 запускал метод A до _complete = true, но не дальше, а затем поток 1 возобновлял и проверял if (_complete) < / strong> - могло ли это if привести к ложному?
volatile
? - person ChaosPandion   schedule 16.08.2010