2016-04-08 16 views
2

Ich habe die threading manual und relevanten MSDN-Seiten und SO questions mehrmals gelesen. Dennoch verstehe ich nicht vollständig, ob Volatile.Read/Write und Interlocked-Operationen nur für die relevanten Variablen oder alle Lese-/Schreibvorgänge vor/nach diesen Operationen gelten..NET Volatile.Read/Write und Interlocked Bereich

Zum Beispiel vorstellen, ich habe ein Array und einen Zähler.

long counter = 0; 
var values = new double[1000000]; 

values[42] = 3.1415; 
// Is this line needed instead of simple assignment above, 
// or the implicit full-fence of Interlocked will guarantee that 
// all threads will see the values[42] after interlocked increment? 
//Volatile.Write(ref values[42], 3.1415); 
Interlocked.Increment(ref counter); 

Does verzahnt Zuwachs garantiert das gleiche Ergebnis wie wenn ich Volatile.Write(ref values[42], 3.1415); anstelle von values[42] = 3.1415;.

Was ist, wenn ich ein Array von Referenztypen, z. einige POCO, und legen Sie eine Instanz Felder vor verriegelten Inkrement. Gilt der implizite vollständige Fence für alle Lese-/Schreibvorgänge von diesem Thread davor oder nur für den Zähler?

ich eine scalable reader/writer scheme bin der Umsetzung und ich fand die folgende Anweisung in der Joe Duffy Beitrag:

Wenn die geschützten Variablen sind Verweise auf Heapobjekte, müssen Sie über die Verwendung des Leseschutz jedes Mal, wenn Sie sich Sorgen zu machen berühren ein Feld. Genau wie Schlösser, komponiert diese Technik nicht. Wie bei allem anderen als einfachen Sperren, verwenden Sie diese Technik mit großer Sorgfalt und Vorsicht; Obwohl die integrierten Zäune zum Abnehmen und Freigeben Sie vor Problemen bei der Umordnung von Speichermodellen schützen, gibt es einige einfache Fallen, in die Sie fallen können.

Ist dies nur eine allgemeine Aussage, um die Verwendung von Low-Lock-Konstrukten zu entmutigen, oder trifft dies irgendwie auf das obige Beispiel zu?

+0

Sie benötigen hier nur eine Semantik zum Akquirieren/Freigeben, um das richtige Verhalten zu erhalten, welches das inkrementelle Inkrement bietet. Die Garantie ist, dass jeder Thread, der den aktualisierten Zähler sieht, auch die fortlaufenden Schreibvorgänge sieht. – Voo

+1

Wenn du es nicht verstehst, solltest du es nie, niemals benutzen. Es wird nicht funktionieren, garantiert. Mit der Bärenfalle, die Sie nicht herausfinden werden, dass es nicht funktioniert, wird nur Ihr Benutzer. Verwenden Sie stattdessen die Klasse ReaderWriterLockSlim, die von jemandem geschrieben wurde, der es verstanden hat und wusste, wie man es so optimal wie möglich macht. –

+0

@HansPassant gibt es so etwas in der Welt namens "Lernen" ... Und SO hilft damit :) Wenn Sie die gesamte Joe Duffy Post-Serie auf Reader-Writer-Lock-Implementierungen lesen, werden Sie feststellen, Reihenfolge der Größenordnung Leistungsdifferenz . –

Antwort

2

Was Sie wahrscheinlich vermissen, ist ein Verständnis von Zäunen. Dies ist die beste Ressource, um sie zu lesen: http://www.albahari.com/threading/part4.aspx

Die kurze Antwort ist Interlocked.Increment gibt einen vollen Zaun, der unabhängig von der Variable ist, die es aktualisiert. Ich glaube, Volatile.Write gibt einen halben Zaun. Ein halber Zaun kann aus Thread.MemoryBarrier konstruiert werden. Wenn wir sagen, Interlocked.Increment gibt einen vollen Zaun aus bedeutet dies, dass Thread.MemoryBarrier vor und nach der Operation aufgerufen wird. Volatile.Write Aufrufe Thread.MemoryBarrier vor dem Schreiben und Volatile.Read nach. Die Zäune bestimmen, wann der Speicherzugriff neu geordnet werden kann (und er ist nicht variabel, da Thread.MemoryBarrier parameterlos ist).

+0

Also bin ich hier sicher? –

+0

Obendrauf ist die Verriegelung ohne zusätzliche Verriegelung atomar. Sie können es nicht ohne eine Sperre mit einer anderen Operation wiederholen, da sich der Wert zwischen Lesen und Schreiben ändern kann. Ja, du bist in Sicherheit. – TomTom

+0

Es wäre überflüssig, 'Thread.MemoryBarrier' zwischen den Aufruf von' values ​​[42] = 3.1415; 'und' Interlocked.Increment (ref counter); 'zu setzen, sodass das Hinzufügen von Volatile.Write Ihrem Code nichts hinzufügt. Aber Sie sollten wahrscheinlich den Link lesen, den ich zur Verfügung gestellt habe. Wenn 'values ​​[42]' aus einem anderen Thread gelesen werden könnten, könnte dies zu einem Lesefehler führen, es sei denn, Sie verwenden eine garantierte atomare Operation zum Lesen/Schreiben. Ich glaube nicht, dass die CLR irgendwelche Garantien über die Atomarität des Lesens/Schreibens einer doppelt übergreifenden Plattformarchitektur bietet (zum Beispiel ein Double als zwei 32 Bit Werte auf einer 32 Bit Plattform betrachten). – keith