Datensynchronisierung für Multithreading
Aktualisiert: November 2007
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.
Synchronized-Eigenschaft. Einige Klassen, z. B. Hashtable und Queue, stellen eine Synchronized-Eigenschaft bereit, die einen threadsicheren Wrapper für eine Instanz der Klasse zurückgibt. Informationen hierzu finden Sie unter Auflistungen und Synchronisierung (Threadsicherheit).
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.
Hinweis: |
---|
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 Hinweis: |
---|
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
Konzepte
Übersicht über Synchronisierungsprimitiven