Datensynchronisierung für Multithreading

Wenn mehrere Threads die Eigenschaften und Methoden eines einzelnen Objekts aufrufen können, müssen diese Aufrufe synchronisiert werden. Andernfalls kann es vorkommen, dass ein Thread die Aktionen eines anderen Threads unterbricht und dadurch einen unzulässigen Zustand für das Objekt verursacht. Eine Klasse, deren Member vor derartigen Unterbrechungen geschützt sind, wird als threadsicher bezeichnet.

Die Common Language-Infrastruktur stellt verschiedene Strategien bereit, um den Zugriff auf Instanzmember und statische Member zu synchronisieren:

  • Synchronisierte Codebereiche. Durch die Monitor-Klasse oder die Compilerunterstützung für diese Klasse werden nur die erforderlichen Codeblöcke synchronisiert, wodurch die Leistung gesteigert wird.

  • Manuelle Synchronisierung. Sie können die von der .NET Framework-Klassenbibliothek bereitgestellten Synchronisierungsobjekte verwenden. Weitere Informationen finden Sie unter Übersicht über Synchronisierungsprimitiven. In diesem Thema wird auch die Monitor-Klasse behandelt.

  • Synchronisierte Kontexte. Durch SynchronizationAttribute wird eine einfache, automatische Synchronisierung von ContextBoundObject-Objekten ermöglicht.

  • Auflistungsklassen im System.Collections.Concurrent-Namespace. Diese Klassen stellen integrierte synchronisierte Vorgänge zum Hinzufügen und Entfernen bereit. Weitere Informationen hierzu finden Sie unter Threadsichere Auflistungen.

Von der Common Language Runtime wird ein Threadmodell bereitgestellt, in dem Klassen verschiedenen Kategorien zugeordnet werden, die je nach Anforderung auf verschiedene Weise synchronisiert werden können. In der folgenden Tabelle wird gezeigt, welche Synchronisierung bei Feldern und Methoden der jeweiligen Synchronisierungskategorie unterstützt wird.

Kategorie

Globale Felder

Statische Felder

Statische Methoden

Instanzfelder

Instanzmethoden

Spezifische Codeblöcke

Keine Synchronisierung

Nein

Nein

Nein

Nein

Nein

Nein

Synchronisierter Kontext

Nein

Nein

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 beliebige Thread kann jederzeit auf alle Methoden oder Felder zugreifen. Es sollte jedoch nur jeweils ein Thread auf diese Objekte zugreifen.

Manuelle Synchronisierung

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

Synchronisierte Codebereiche

Durch die Monitor-Klasse oder ein Compilerschlüsselwort können Codeblöcke, Instanzmethoden und statische Methoden synchronisiert werden. Synchronisierte statische Felder werden nicht unterstützt.

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 zu übernehmen. Wenn bereits ein anderer Thread die Sperre übernommen hat, wird der Thread blockiert, bis die Sperre verfügbar ist. Wenn der Thread den synchronisierten Codeblock beendet, wird die Sperre freigegeben, unabhängig davon, wie der Thread den Block beendet.

HinweisHinweis

Die lock- und SyncLock-Anweisungen werden mit Monitor.Enter und Monitor.Exit implementiert, sodass andere Methoden von Monitor zusammen mit ihnen im synchronisierten Bereich verwendet werden können.

Sie können eine Methode auch mit MethodImplAttribute und MethodImplOptions.Synchronized ergänzen. Das hat denselben Effekt wie Monitor oder eines der Compilerschlüsselwörter, um den gesamten Methodentext zu sperren.

Thread.Interrupt kann verwendet werden, um einen Thread aus blockierten Vorgängen herauszulösen, z. B. bei Wartezeiten während des Zugriffs auf einen synchronisierten Codebereich. Thread.Interrupt wird auch zum Befreien von Threads aus Vorgängen wie Thread.Sleep verwendet.

Wichtiger HinweisWichtig

Sperren Sie nicht den Typ (typeof(MyType) in C#, GetType(MyType) in Visual Basic oder MyType::typeid in C++), um static-Methoden zu schützen (Shared-Methoden in Visual Basic).Verwenden Sie stattdessen ein privates statisches Objekt.Genauso sollten Sie this in C# (Me in Visual Basic) nicht zum Sperren von Instanzmethoden verwenden.Verwenden Sie stattdessen ein privates Objekt.Eine Klasse oder Instanz kann von fremdem Code gesperrt werden, der Deadlocks oder Leistungseinbußen verursachen kann.

Compilerunterstützung

Sowohl Visual Basic als auch C# unterstützen ein Sprachschlüsselwort, das das Objekt mit Monitor.Enter und Monitor.Exit sperrt. Visual Basic unterstützt die SyncLock-Anweisung, C# die lock-Anweisung.

In beiden Fällen wird eine Ausnahme im Codeblock ausgelöst. Die durch lock oder SyncLock erlangte Sperre wird automatisch freigegeben. Die Compiler von C# und Visual Basic geben einen try/finally-Block aus, wobei Monitor.Enter am Anfang des try-Blocks und Monitor.Exit im finally-Block enthalten ist. Wenn innerhalb des lock- oder SyncLock-Blocks eine Ausnahme ausgelöst wird, wird die Bereinigung durch den finally-Handler ermöglicht.

Synchronisierter Kontext

Durch Anwendung von SynchronizationAttribute auf ein beliebiges ContextBoundObject können alle Instanzmethoden und -felder synchronisiert werden. Alle Objekte derselben Kontextdomäne nutzen dieselbe Sperre. Mehrere Threads können auf die Methoden und Felder zugreifen, jedoch immer nur ein einzelner Thread gleichzeitig.

Siehe auch

Referenz

SyncLock-Anweisung

lock-Anweisung (C#-Referenz)

SynchronizationAttribute

Konzepte

Threads und Threading

Übersicht über Synchronisierungsprimitiven