Datensynchronisierung für Multithreading

Wenn mehrere Threads die Eigenschaften und Methoden eines einzelnen Objekts aufrufen können, ist es wichtig, dass diese Aufrufe synchronisiert werden. Andernfalls kann ein Thread möglicherweise die Aufgabe eines anderen Threads unterbrechen, und das Objekt bleibt womöglich in einem ungültigen Status zurück. Eine Klasse, deren Mitglieder vor solchen Unterbrechungen geschützt, wird threadsicher genannt.

.NET stellt verschiedene Strategien zum Synchronisieren des Zugriffs auf Instanzmember und statische Member bereit:

  • Synchronisierte Codebereiche. Sie können die Monitor-Klasse oder die Compilerunterstützung für diese Klasse zum Synchronisieren von einzig und allein dem Codeblock verwenden, der sie benötigt, wobei die Leistung verbessert wird.

  • Manuelle Synchronisierung Sie können die von der .NET-Klassenbibliothek bereitgestellten Synchronisierungsobjekte verwenden. Unter Übersicht über Synchronisierungsprimitiven finden Sie weitere Informationen, darunter eine Beschreibung der Monitor-Klasse.

  • Synchronisierte Kontexte. Sie können die SynchronizationAttribute-Klasse nur im Zusammenhang mit .NET Framework- und Xamarin-Anwendungen verwenden, um eine einfache automatische Synchronisierung für ContextBoundObject-Objekte zu ermöglichen.

  • Auflistungsklassen im System.Collections.Concurrent-Namespace. Diese Klassen stellen integrierte synchronisierte Hinzufüge- und Entfernungsvorgänge bereit. Weitere Informationen finden Sie unter Threadsichere Auflistungen.

Die Common Language Runtime stellt ein Threadmodell bereit, bei dem Klassen in verschiedene Kategorien fallen, die je nach den Anforderungen in einer Vielzahl von Möglichkeiten synchronisiert werden können. Die folgende Tabelle zeigt, welche Synchronisierungsunterstützung für Felder und Methoden mit einer angegebenen Synchronisierungskategorie vorhanden sind.

Kategorie Globale Felder Statische Felder Statische Methoden Instanzfelder Instanzmethoden Spezifische Codeblöcke
Keine Synchronisierung Nein Nr. Nr. Nr. Nr. Nein
Synchronisierter Kontexte Nein Nr. Nein Ja Ja Nein
Synchronisierte Codebereiche Nein Nein Nur wenn markiert Nein Nur wenn markiert Nur wenn markiert
Manuelle Synchronisierung Manuell Manuell Manuell Manuell Manuell Manuell

Keine Synchronisierung

Dies ist die Standardeinstellung für Objekte. Jeder Thread kann jederzeit auf alle Methoden oder Felder zugreifen. Es sollte jedoch nur ein Thread nach dem anderen auf diese Objekte zugreifen.

Manuelle Synchronisierung

Die .NET-Klassenbibliothek stellt eine Reihe von Klassen zum Synchronisieren von Threads bereit. Weitere Informationen finden Sie unter Übersicht über Synchronisierungsprimitiven.

Synchronisierte Codebereiche

Sie können die Monitor-Klasse oder ein Compilerschlüsselwort zur Synchronisierung von Codeblöcken, Instanzmethoden und statischen Methoden verwenden. Es gibt keine Unterstützung für synchronisierte statische Felder.

Visual Basic und C# unterstützen das Markieren von Codeblöcken mit einem bestimmten Sprachschlüsselwort, der lock-Anweisung in C# oder der SyncLock-Anweisung in Visual Basic. Wenn der Code von einem Thread ausgeführt wird, wird versucht, die Sperre abzurufen. Wenn die Sperre bereits von einem anderen Thread abgerufen wurde, wird der Thread blockiert, bis die Sperre verfügbar ist. Wenn der Thread den synchronisierten Codeblock beendet, wird die Sperre aufgehoben, unabhängig davon, wie der Thread den Block beendet.

Hinweis

Die lock- und SyncLock-Anweisung werden mit Monitor.Enter und Monitor.Exitimplementiert, sodass andere Methoden von Monitor in Verbindung mit ihnen im synchronisierten Bereich verwendet werden können.

Sie können eine Methode auch mit einem MethodImplAttribute-Element mit dem Wert MethodImplOptions.Synchronized versehen. Dies hat die gleiche Auswirkung wie die Verwendung von Monitor oder von einem der Compilerschlüsselwörter zum Sperren des gesamten Texts der Methode.

Thread.Interrupt kann verwendet werden, um einen Thread aus blockierten Vorgängen zu unterbrechen, wie z.B. das Warten auf Zugriff auf einen synchronisierten Codebereich. Thread.Interrupt dient außerdem zum Unterbrechen von Threads von Vorgängen wie Thread.Sleep aus.

Wichtig

Sperren Sie nicht den Typ – d.h. typeof(MyType) in C#, GetType(MyType) in Visual Basic oder MyType::typeid in C++ – um die static-Methoden zu schützen (Shared-Methoden in Visual Basic). Verwenden Sie stattdessen ein privates statisches Objekt. Verwenden Sie auch nicht this in C# (Me in Visual Basic), um Instanzmethoden zu sperren. Verwenden Sie stattdessen ein privates Objekt. Eine Klasse oder Instanz kann von einem anderen Code als Ihrem eigenen gesperrt werden, was potenziell zu Deadlocks oder Leistungsproblemen führt.

Compilerunterstützung

Visual Basic und C# unterstützen ein Sprachschlüsselwort, das Monitor.Enter und Monitor.Exit zum Sperren des Objekts verwendet. Visual Basic unterstützt die SyncLock-Anweisung und C# unterstützt die lock-Anweisung.

Wenn eine Ausnahme im Codeblock ausgelöst wird, wird in beiden Fällen die Sperre, die durch lock oder SyncLock erstellt wurde, automatisch aufgehoben. Die C#- und Visual Basic-Compiler geben einen try/finally-Block mit Monitor.Enter zu Beginn des Versuchs und Monitor.Exit im finally-Block aus. Wenn eine Ausnahme innerhalb eines lock- oder SyncLock-Blocks ausgelöst wird, wird der finally-Handler ausgeführt, damit Sie notwendige Bereinigungen ausführen können.

Synchronisierter Kontexte

Ausschließlich in .NET Framework- und Xamarin-Anwendungen können Sie das SynchronizationAttribute-Element für beliebige ContextBoundObject-Elemente verwenden, um alle Instanzmethoden und -felder zu synchronisieren. Alle Objekte in der gleichen Kontextdomäne teilen die gleiche Sperre. Mehrere Threads können auf die Methoden und Felder zugreifen, jedoch ist nur ein einzelner Thread gleichzeitig zulässig.

Siehe auch