C# 4 in sintesi (altamente consigliato btw) utilizza il seguente codice per dimostrare il concetto di MemoryBarrier (supponendo A e B sono stati eseguiti su diversi thread):Perché ho bisogno di una barriera di memoria?
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);
}
}
}
accennano che Barriere 1 & 4 impediscono questa esempio da scrittura 0 e Barriere 2 & 3 fornire una garanzia freschezza: assicurano che se B correva dopo A, leggendo _completo valuterebbe a vero.
Non lo capisco davvero. Credo di capire il motivo per cui le barriere 1 & 4 sono necessari: non vogliamo la scrittura a _answer di ottimizzare e collocati dopo la scrittura per _complete (Barriera 1) e dobbiamo fare in modo che _answer è non memorizzato nella cache (barriera 4). Penso anche di capire perché è necessario Barrier 3: se A funzionasse solo dopo aver scritto _complete = true, B avrebbe comunque bisogno di aggiornare _completo per leggere il valore corretto.
Non capisco però perché abbiamo bisogno di Barriera 2! Una parte di me dice che forse il thread 2 (in esecuzione B) è già stato eseguito (ma non incluso) se (_completato) e quindi è necessario assicurare che _completo sia aggiornato.
Tuttavia, non vedo come questo aiuti. Non è ancora possibile che _completo sia impostato su true in A, ma il metodo B vedrà una versione cache (falsa) di _completo? Per esempio, se filettatura 2 riceve un metodo B fino a dopo la prima MemoryBarrier e poi filetto 1 corse metodo A fino _complete = true ma non oltre, e poi filetto 1 riprende e testato se (_complete) - potrebbe che se non risulta in false?
Perché qualcuno dovrebbe usarlo su 'volatile'? – ChaosPandion
@Chaos: CLR tramite C# book (Richter) ha una grande spiegazione - IIRC è che 'volatile' significa che tutti gli accessi al var sono trattati come volatili e impongono barriere di memoria complete in entrambe le direzioni. Questo è spesso il modo più perfetto del necessario se invece hai solo bisogno di una barriera di lettura o di scrittura e solo in particolari accessi. –
@Chaos: non proprio il punto, ma una ragione è che volatile ha le sue peculiarità riguardo alle ottimizzazioni del compilatore che potrebbero portare a deadlock, vedere http://www.bluebytesoftware.com/blog/2009/02/24/TheMagicalDuelingDeadlockingSpinLocks .aspx – hackerhasid