Hier gibt es zahlreiche Fragen. Betrachten Sie sie einzeln:
Die Referenzzuweisung ist atomar. Warum wird Interlocked.Exchange (ref Object, Object) benötigt?
Die Referenzzuordnung ist atomar. Interlocked.Exchange führt nicht nur die Referenzzuweisung durch. Es liest den aktuellen Wert einer Variablen, versteckt den alten Wert und weist der Variablen den neuen Wert als atomare Operation zu.
Mein Kollege sagte, dass auf einigen Plattformen nicht garantiert werden kann, dass die Referenzzuweisung atomar ist. War mein Kollege richtig?
Nein. Die Referenzzuweisung ist auf allen .NET-Plattformen garantiert atomar.
Mein Kollege argumentiert aus falschen Prämissen. Bedeutet das, dass ihre Schlussfolgerungen falsch sind?
Nicht unbedingt. Ihr Kollege könnte Ihnen aus schlechten Gründen gute Ratschläge geben. Vielleicht gibt es einen anderen Grund, warum Sie Interlocked.Exchange verwenden sollten. Lock-free-Programmierung ist wahnsinnig schwierig und sobald Sie von etablierten Praktiken abweichen, die von Experten auf diesem Gebiet vertreten werden, sind Sie im Unkraut und riskieren die schlimmsten Rennbedingungen. Ich bin weder ein Experte auf diesem Gebiet noch ein Experte für Ihren Code, daher kann ich auf die eine oder andere Weise kein Urteil fällen.
erzeugt eine Warnung "Ein Verweis auf ein flüchtiges Feld wird nicht als flüchtig behandelt" Was soll ich darüber denken?
Sie sollten verstehen, warum dies im Allgemeinen ein Problem ist. Dies führt zu einem Verständnis dafür, warum die Warnung in diesem speziellen Fall unwichtig ist.
Der Grund, warum der Compiler diese Warnung ausgibt, liegt darin, dass das Markieren eines Felds als flüchtig bedeutet, dass dieses Feld in mehreren Threads aktualisiert wird. Generieren Sie keinen Code, der die Werte dieses Felds zwischenspeichert, und stellen Sie sicher, dass Lese- oder Schreibvorgänge ausgeführt werden Dieses Feld wird nicht "zeitlich vorwärts und rückwärts verschoben" über Prozessor-Cache-Inkonsistenzen.
(Ich gehe davon aus, dass Sie das alles bereits verstehen. Wenn Sie nicht genau wissen, was flüchtig ist und wie es sich auf die Semantik des Prozessor-Cache auswirkt, verstehen Sie nicht, wie es funktioniert, und sollten keine flüchtigen Programme verwenden. Sperrfreie Programme sind sehr schwer zu finden; stellen Sie sicher, dass Ihr Programm richtig ist, weil Sie verstehen, wie es funktioniert, nicht zufällig.)
Angenommen, Sie erstellen eine Variable, die ein Alias eines flüchtigen Feldes ist, indem Sie einen Verweis an dieses Feld übergeben. Innerhalb der aufgerufenen Methode hat der Compiler überhaupt keinen Grund zu wissen, dass die Referenz eine flüchtige Semantik haben muss! Der Compiler generiert fröhlich Code für die Methode, die die Regeln für flüchtige Felder nicht implementiert, aber die Variable ist ein flüchtiges Feld. Das kann Ihre sperrfreie Logik völlig ruinieren. Die Annahme ist immer, dass auf ein flüchtiges Feld immer mit flüchtiger Semantik zugegriffen wird. Es macht keinen Sinn, es manchmal und manchmal nicht als flüchtig zu behandeln. du musst immer konsistent sein, sonst können Sie keine Konsistenz für andere Zugriffe garantieren.
Daher warnt der Compiler, wenn Sie dies tun, da dies wahrscheinlich Ihre sorgfältig entwickelte sperrfreie Logik völlig durcheinander bringen wird.
Natürlich ist Interlocked.Exchange so geschrieben, dass es ein volatiles Feld erwartet und das Richtige tut. Die Warnung ist daher irreführend. Ich bedauere das sehr; Was wir hätten tun sollen, ist einen Mechanismus zu implementieren, mit dem ein Autor einer Methode wie Interlocked.Exchange der Methode ein Attribut hinzufügen kann, das besagt: "Diese Methode, die einen Ref benötigt, erzwingt eine flüchtige Semantik für die Variable, also unterdrücken Sie die Warnung." Vielleicht werden wir dies in einer zukünftigen Version des Compilers tun.
var myresult = await Task.Factory.CreateNew(() => MyWork(exclusivelyLocalStuffOrValueTypeOrCopy));
.Entweder irrt sich Ihr Kollege oder er weiß etwas, was die C # -Sprachenspezifikation nicht weiß.
5.5 Atomizität variabler Referenzen :
Sie können also in die flüchtige Referenz schreiben, ohne das Risiko, einen beschädigten Wert zu erhalten.
Sie sollten natürlich vorsichtig sein, wie Sie entscheiden, welcher Thread die neuen Daten abrufen soll, um das Risiko zu minimieren, dass mehr als ein Thread dies gleichzeitig tut.
quelle
Interlocked.Exchange <T>
Es ändert sich und gibt den ursprünglichen Wert zurück. Es ist nutzlos, weil Sie es nur ändern möchten, und wie Guffa sagte, ist es bereits atomar.
Wenn ein Profiler nicht nachgewiesen hat, dass es sich um einen Engpass in Ihrer Anwendung handelt, sollten Sie in Betracht ziehen, Sperren zu deaktivieren. Es ist einfacher zu verstehen und zu beweisen, dass Ihr Code richtig ist.
quelle
Iterlocked.Exchange()
ist nicht nur atomar, sondern sorgt auch für die Sichtbarkeit des Gedächtnisses:Synchronisations- und Multiprozessorprobleme
Dies bedeutet, dass zusätzlich zur Atomizität Folgendes sichergestellt wird:
quelle