2012-09-14 8 views
19

Qual è la differenza tra Interlocked.Exchange e Volatile.Write?differenza tra Interlocked.Exchange e Volatile.Write?

Entrambi i metodi aggiornano il valore di alcune variabili. Qualcuno può riassumere quando utilizzare ciascuno di essi?

http://msdn.microsoft.com/ru-ru/library/bb337971 e http://msdn.microsoft.com/en-us/library/gg712713.aspx

In particolare ho bisogno di aggiornare doppio punto della mia matrice, e voglio un altro thread per vedere il valore più fresco. Qual è il preferito? Interlocked.Exchange(ref arr[3], myValue) o Volatile.Write(ref arr[3], info); dove arr è dichiarato come double?

========================================= ============================== esempio reale, dichiaro doppio array del genere:

private double[] _cachedProduct; 

In una filettatura I aggiorno così:

 _cachedProduct[instrumentId] = calcValue; 
     ... 
     are.Set(); 

In un'altra discussione ho letto questa matrice così:

 while(true) { 
      are.WaitOne(); 
      ... 
       result += _cachedProduct[instrumentId]; 
      ... 
     } 

Per me funziona perfettamente così com'è. Tuttavia, per assicurarsi che "funzionerà sempre", a prescindere da ciò che sembra, è necessario aggiungere Volatile.Write o Interlocked.Exchange. Perché il doppio aggiornamento non è garantito per essere atomico http://msdn.microsoft.com/en-us/library/aa691278%28VS.71%29.aspx

Nella risposta a questa domanda voglio vedere un confronto dettagliato delle classi Volatile e Interlocked. Perché abbiamo bisogno di 2 lezioni? Quale e quando usare?

+0

Non è possibile utilizzare Volatile.Write in questo caso specifico: accetta solo tipi di riferimento, non tipi di valore. –

+0

Si sta utilizzando un handle di attesa, già * garantisce * che l'altro thread visualizzi completamente il valore più recente. * * Funzionerà sempre. – harold

risposta

11

l'Interlocked.Exchange utilizza un'istruzione del processore che garantisce un'operazione atomica.

Volatile.Write fa lo stesso ma include anche un'operazione di barriera di memoria. Penso che Microsoft abbia aggiunto Volatile.Write su DotNet 4.5 grazie al supporto dei processori ARM su Windows 8. I processori Intel e ARM differiscono sul riordino delle operazioni di memoria.

Su Intel, si garantisce che le operazioni di accesso alla memoria verranno eseguite nello stesso ordine in cui sono state emesse, o almeno che un'operazione di scrittura non verrà riordinata.

Da Intel® 64 e IA-32 Architetture Manuale dello sviluppatore di software, Capitolo 8:

8.2.2 Memoria ordinazione in P6 e più famiglie di processori recenti Il processore Intel Core 2 Duo, Intel Atom, Intel Core Duo , I processori della famiglia Pentium 4 e P6 utilizzano anche un modello di ordinamento della memoria ordinato dal processore che può essere definito ulteriormente come "ordina con l'inoltro del buffer del magazzino". Questo modello può essere caratterizzato come segue.

Su ARM non si dispone di questo tipo di garanzia, quindi è necessaria una barriera di memoria. Un blog ARM che lo spiega può essere trovato qui: http://blogs.arm.com/software-enablement/594-memory-access-ordering-part-3-memory-access-ordering-in-the-arm-architecture/

Nel tuo esempio, poiché l'operazione con doppio non è garantita per essere atomica, consiglierei un blocco per accedervi. Ricordare che è necessario utilizzare il blocco su entrambe le parti del codice, durante la lettura e l'impostazione del valore.

Un esempio più completo sarebbe meglio rispondere alla tua domanda, in quanto non è chiaro cosa succede dopo aver impostato questi valori. Per un vettore, se avete più lettori che scrittori, considerate l'uso di un oggetto ReaderWriterLockSlim: http://msdn.microsoft.com/en-us/library/system.threading.readerwriterlockslim.aspx

Il numero di thread e la frequenza di lettura/scrittura possono cambiare drasticamente la vostra strategia di blocco.

+0

Non voglio usare il blocco, perché un sistema x64 "doppio aggiornamento" è probabilmente atomico e quindi non voglio introdurre latenza aggiuntiva che non è richiesta. questo è un codice molto sensibile al tempo, quindi voglio davvero vincere diversi microsecondi extra. – javapowered

+0

hm quindi "Volatile.Write' garantisce l'atomicità. msdn non dice nulla a riguardo. perché suggerisci di usare 'lock'? perché non usare 'Interlock.Exchage' o' Volatile'? – javapowered

+0

Ho usato la descrizione della classe Volatile per basare la mia risposta. Un buon articolo sulla differenza tra atomico, volatile può essere trovato qui: http://blogs.msdn.com/b/ericlippert/archive/2011/05/26/atomicity-volatility-and-immutability-are-different-part -one.aspx? PageIndex = 2 Ho controllato la definizione del linguaggio C# 4.0. Nella sezione 5.5, non hanno aggiornato il documento per includere il doppio come operazione atomica. Hai chiesto un modo per garantire che funzionasse sempre, quindi una serratura è una tale garanzia. Nel caso specifico del tuo esempio, dipenderà da quale thread incrementa instrumentId – nmenezes