Ich habe in VB.NET eine Zeit lang einfache Multithreading-Operationen durchgeführt und bin gerade in mein erstes großes Multi-Thread-Projekt eingestiegen. Ich habe immer alles mit der Synclock
Anweisung gemacht, weil ich nicht gedacht habe, dass es einen besseren Weg gibt.
Ich habe gerade von der Interlocked
-Klasse erfahren - es sieht so aus, als ob all das:
Kann durch eine einzelne Aussage ersetzt werden:
%Vor%Damit werden alle Sperren intern bearbeitet und die Nummer geändert. Dies wäre viel einfacher als das Schreiben meiner eigenen Sperren für einfache Operationen (länger laufende oder kompliziertere Operationen benötigen offensichtlich immer noch ihre eigene Sperre).
Gibt es einen Grund, warum ich meine eigene Sperre mit dedizierten Sperrobjekten rolle, wenn ich das gleiche mit den Interlocked
-Methoden erreichen kann?
Die kurze Antwort ist, weil die Verwendung einer Monitor
lock ( SyncLock
in VB und lock { }
in C #) nicht nur sicherstellt, dass immer nur ein Thread auf die Variable zugreifen kann (oder streng genommen nur Ein Thread zu einer Zeit kann eine Sperre für das Sperrobjekt erhalten), aber es erstellt auch die Speicherbarriere, die erforderlich ist, um sicherzustellen, dass Lesevorgänge auf der Variablen nicht weg optimiert werden.
Wenn Sie nie nur den Wert der Variablen lesen (mit anderen Worten, Ihre gesamte Arbeit wird durch Aufrufe von Interlocked
erledigt), dann sind Sie in Ordnung. Wenn Sie jedoch ein normales Lesen der Variablen durchführen müssen, ist die Situation komplizierter. Lockless-Lese- / Schreibvorgänge werden normalerweise in C # mithilfe des Schlüsselworts volatile
ausgeführt. Dies weist den Compiler an, den Wert der Variablen überall dort zu lesen, wo er gerade verwendet wird, anstatt diese Lesevorgänge in einen lokalen Cache zu optimieren. Leider gibt es in VB.NET kein Äquivalent, Sie müssen also etwas anderes verwenden.
Die akzeptierte Antwort auf diese Frage sollte einige weitere Informationen zu dem bieten, was Sie tun können machen. Kurz gesagt, die meisten Leute verwenden SyncLock
in VB.NET, weil es einfacher und weniger kompliziert ist als die Logik, die dazu benötigt wird ohne SyncLock
.
Ich habe einmal eine sehr gute Erklärung für so genannte nicht-atomare und atomare (in VB: verriegelte) Operationen gelesen und werde versuchen, das zusammenzufassen.
%Vor%- & gt; andere Threads können zwischen diesen Strips arbeiten
%Vor%- & gt; andere Threads können keine Arbeit ausführen, während atomare Operationen verarbeitet werden, atomare Operationen werden immer als Ganzes verarbeitet.
Die verriegelte Klasse ist eine Sammlung solcher atomarer Operationen und daher threadsafe definitionsgemäß. Selbst wenn mehrere Threads Lese- und Schreiboperationen für die gleiche Variable ausführen, sind diese Operationen absolut threadsicher.
Dennoch kann eine Kombination dieser threadsafe-Befehle unsicher sein, da zwischen den atomaren Operationen Race-Bedingungen auftreten können.
Wenn Sie zum Beispiel zwei Variablen vergleichen und dann die kleinere erhöhen möchten, ist dies nicht Thread-sicher, obwohl die einzelnen Operationen für sich selbst sind (interlocked.compare, interlocked.increment). Hier müssen Sie noch synclocks verwenden.
Abgesehen von dieser Einschränkung gibt es keine "versteckte, schlechte Seite" von Interlocked.
Ein Beispiel für eine Racecondition mit a = 5:
%Vor%Option 1:
%Vor%oder Option 2:
%Vor%oder Option 3:
%Vor%Mit interlocked.increment:
Option 1:
%Vor%oder Option 2:
%Vor%- & gt; in allen Fällen a = 8 wie angenommen, threadsafe Lösung
Alle Fragen, die hier gepostet wurden, können durch Anwenden dieses einfachen Beispiels auf den fraglichen Code gelöst werden.
Hoffe das hilft anderen Leuten, die dieses Thema googlen. Janis
Interlocked
beschränkt sich auf einfache Operationen auf Integer, Long und Boolean und so weiter.
Wenn Sie beispielsweise ein Element zu einer geteilten Liste (von T) hinzufügen möchten, benötigen Sie weiterhin SynClock
.
Tags und Links .net multithreading locking interlocked synclock