Freigeben über


Übersicht über Synchronisierungsgrundtypen

.NET stellt eine Reihe von Typen bereit, mit denen Sie den Zugriff auf eine freigegebene Ressource oder eine Koordinatenthreadinteraktion synchronisieren können.

Von Bedeutung

Verwenden Sie dieselbe primitive Synchronisierungsinstanz, um den Zugriff auf eine freigegebene Ressource zu schützen. Wenn Sie unterschiedliche Synchronisierungsgrundtypeninstanzen verwenden, um dieselbe Ressource zu schützen, umgehen Sie den Schutz, der durch einen Synchronisierungsgrundtyp bereitgestellt wird.

WaitHandle-Klasse und einfache Synchronisierungstypen

Mehrere .NET-Synchronisierungsgrundtypen werden von der System.Threading.WaitHandle Klasse abgeleitet, die ein systemeigenes Synchronisierungshandle des Betriebssystems kapselt und einen Signalisierungsmechanismus für threadinteraktion verwendet. Zu diesen Klassen gehören:

  • System.Threading.Mutex, das exklusiven Zugang zu einer gemeinsam genutzten Ressource gewährt. Der Zustand eines Mutex wird signalisiert, wenn er nicht in Besitz eines Threads ist.
  • System.Threading.Semaphore, wodurch die Anzahl der Threads begrenzt wird, die gleichzeitig auf eine freigegebene Ressource oder einen Pool von Ressourcen zugreifen können. Der Zustand eines Semaphors wird so festgelegt, dass er signalisiert wird, wenn seine Anzahl größer als Null ist und nicht signalisiert wird, wenn die Anzahl null ist.
  • System.Threading.EventWaitHandle, das ein Threadsynchronisierungsereignis darstellt und entweder in einem signalierten oder nicht signalisierten Zustand sein kann.
  • System.Threading.AutoResetEvent wird aus EventWaitHandle abgeleitet und wird nach der Freigabe eines einzelnen wartenden Threads automatisch in einen nicht signalisierten Zustand zurückgesetzt, wenn einen Signalisierung eintritt.
  • System.Threading.ManualResetEvent, das von EventWaitHandle abgeleitet wird und, wenn signalisiert, in einem signalierten Zustand bleibt, bis die Reset-Methode aufgerufen wird.

Da WaitHandle vom System.MarshalByRefObject abgeleitet ist, können diese Typen in .NET Framework verwendet werden, um die Aktivitäten von Threads über die Grenzen von Anwendungsdomänen hinweg zu synchronisieren.

In .NET Framework, .NET Core und .NET 5+ können einige dieser Typen benannte Systemsynchronisierungshandles darstellen, die im gesamten Betriebssystem sichtbar sind und für die Prozessübergreifende Synchronisierung verwendet werden können:

Weitere Informationen finden Sie in der WaitHandle API-Referenz.

Einfache Synchronisierungstypen basieren nicht auf zugrunde liegende Betriebssystemhandles und bieten in der Regel eine bessere Leistung. Sie können jedoch nicht für die Prozessübergreifende Synchronisierung verwendet werden. Verwenden Sie diese Typen für die Threadsynchronisierung innerhalb einer Anwendung.

Einige Typen davon sind Alternativen zu den von WaitHandle abgeleiteten Typen. Beispielsweise SemaphoreSlim ist eine einfache Alternative zu Semaphore.

Synchronisierung des Zugriffs auf eine freigegebene Ressource

.NET bietet eine Reihe von Synchronisierungsgrundtypen, um den Zugriff auf eine freigegebene Ressource durch mehrere Threads zu steuern.

Monitorklasse

Die System.Threading.Monitor Klasse gewährt exklusiven Zugriff auf eine gemeinsam genutzte Ressource, indem eine Sperre für das Objekt, das die Ressource identifiziert, erworben oder freigegeben wird. Während eine Sperre gehalten wird, kann der Thread, der die Sperre enthält, die Sperre erneut abrufen und freigeben. Jeder andere Thread wird daran gehindert, die Sperre zu erhalten, und die Monitor.Enter Methode wartet, bis die Sperre losgelassen wird. Die Enter-Methode ruft eine freigegebene Sperre ab. Sie können die Monitor.TryEnter-Methode auch verwenden, um die Zeitspanne anzugeben, in der ein Thread versucht, eine Sperre abzurufen. Da die Monitor-Klasse Threadaffinität hat, muss der Thread, der eine Sperre erhalten hat, die Sperre durch Aufruf der Monitor.Exit-Methode freigeben.

Sie können die Interaktion von Threads koordinieren, die eine Sperre für dasselbe Objekt abrufen, indem Sie die Methoden Monitor.Wait, Monitor.Pulse und Monitor.PulseAll verwenden.

Weitere Informationen finden Sie in der Monitor API-Referenz.

Hinweis

Verwenden Sie die Lock-Anweisung in C# und die SyncLock-Anweisung in Visual Basic, um den Zugriff auf eine freigegebene Ressource zu synchronisieren, anstatt die Monitor Klasse direkt zu verwenden. Diese Anweisungen werden durch die Enter- und Exit-Methoden sowie einen try…finally-Block implementiert, um sicherzustellen, dass die erworbene Sperre immer freigegeben wird.

Mutex-Klasse

Die System.Threading.Mutex-Klasse, wie Monitor, gewährt exklusiven Zugriff auf eine freigegebene Ressource. Verwenden Sie eine der Mutex.WaitOne-Methodenüberladungen, um den Besitz eines Mutex anzufordern. Wie Monitor, Mutex hat Threadaffinität und der Thread, der ein Mutex erworben hat, muss es freigeben, indem die Mutex.ReleaseMutex Methode aufgerufen wird.

Im Gegensatz zu Monitor kann die Mutex Klasse für die prozessübergreifende Synchronisierung verwendet werden. Verwenden Sie dazu einen benannten Mutex, der im gesamten Betriebssystem sichtbar ist. Verwenden Sie einen Mutex-Konstruktor , der einen Namen angibt, um eine benannte Mutex-Instanz zu erstellen. Sie können auch die Mutex.OpenExisting-Methode aufrufen, um einen vorhandenen benannten System-Mutex zu öffnen.

Weitere Informationen finden Sie im Artikel "Mutexes" und in der Mutex API-Referenz.

SpinLock-Struktur

Die System.Threading.SpinLock-Struktur, wie z. B. Monitor, gewährt exklusiven Zugriff auf eine freigegebene Ressource basierend auf der Verfügbarkeit einer Sperre. Wenn SpinLock versucht, eine nicht verfügbare Sperre zu erhalten, wartet sie in einer Schleife und überprüft wiederholt, ob die Sperre verfügbar ist.

Weitere Informationen zu den Vorteilen und Nachteilen der Verwendung von Spin Lock finden Sie im SpinLock-Artikel und in der SpinLock API-Referenz.

ReaderWriterLockSlim-Klasse

Die System.Threading.ReaderWriterLockSlim Klasse gewährt exklusiven Zugriff auf eine freigegebene Ressource zum Schreiben und ermöglicht es mehreren Threads, gleichzeitig auf die Ressource zum Lesen zuzugreifen. Möglicherweise möchten Sie ReaderWriterLockSlim verwenden, um den Zugriff auf eine freigegebene Datenstruktur zu synchronisieren, die threadsichere Lesevorgänge unterstützt, jedoch exklusiven Zugriff für Schreibvorgänge erfordert. Wenn ein Thread exklusiven Zugriff anfordert (z. B. durch Aufrufen der ReaderWriterLockSlim.EnterWriteLock Methode), werden nachfolgende Lese- und Writer-Anforderungen blockiert, bis alle vorhandenen Leser die Sperre beendet haben, und der Writer hat die Sperre eingegeben und beendet.

Weitere Informationen finden Sie in der ReaderWriterLockSlim API-Referenz.

Semaphore- und SemaphoreSlim-Klassen

Die Klassen System.Threading.Semaphore und System.Threading.SemaphoreSlim beschränken die Anzahl der Threads, die gleichzeitig auf eine gemeinsame Ressource oder einen Pool von Ressourcen zugreifen könnten. Zusätzliche Threads, die die Ressource anfordern, warten, bis ein Thread den Semaphor freigibt. Da der Semaphor keine Threadaffinität hat, kann ein Thread das Semaphor erwerben und ein anderer kann ihn freigeben.

SemaphoreSlim ist eine einfache Alternative zu Semaphore und kann nur für die Synchronisierung innerhalb einer einzigen Prozessgrenze verwendet werden.

Unter Windows können Sie die prozessübergreifende Synchronisierung verwenden Semaphore . Erstellen Sie dazu eine Semaphore Instanz, die einen benannten System-Semaphor darstellt, indem Sie einen der Semaphor-Konstruktoren verwenden, der einen Namen oder die Semaphore.OpenExisting Methode angibt. SemaphoreSlim unterstützt keine benannten Systemsemaphoren.

Weitere Informationen finden Sie im Artikel "Semaphore" und "SemaphoreSlim" und in der Semaphore API-Referenz SemaphoreSlim .

Threadinteraktion oder Signalisierung

Threadinteraktion (oder Threadsignalisierung) bedeutet, dass ein Thread auf eine Benachrichtigung oder ein Signal von einem oder mehreren Threads warten muss, um fortzufahren. Wenn Thread A beispielsweise die Thread.Join Methode von Thread B aufruft, wird Thread A blockiert, bis Thread B abgeschlossen ist. Die im vorhergehenden Abschnitt beschriebenen Synchronisierungsprimitive bieten einen anderen Mechanismus für die Signalisierung: Durch die Freigabe einer Sperre benachrichtigt ein Thread einen anderen Thread, dass er durch den Erhalt der Sperre fortgesetzt werden kann.

In diesem Abschnitt werden zusätzliche Signalisierungskonstrukte beschrieben, die von .NET bereitgestellt werden.

EventWaitHandle-, AutoResetEvent-, ManualResetEvent- und ManualResetEventSlim-Klassen

Die System.Threading.EventWaitHandle Klasse stellt ein Threadsynchronisierungsereignis dar.

Ein Synchronisierungsereignis kann sich entweder in einem nicht signalisierten oder signalisierten Zustand befinden. Wenn der Status eines Ereignisses nicht signalisiert wird, wird ein Thread, der die Überladung des Ereignisses WaitOne aufruft, blockiert, bis ein Ereignis signalisiert wird. Die EventWaitHandle.Set Methode legt den Zustand eines Ereignisses fest, das signalisiert wird.

Das Verhalten einer signalisierten EventWaitHandle hängt von den Zurücksetzmodus ab:

Unter Windows können Sie die prozessübergreifende Synchronisierung verwenden EventWaitHandle . Erstellen Sie dazu eine EventWaitHandle Instanz, die ein benanntes Systemsynchronisierungsereignis darstellt, indem Sie einen der EventWaitHandle-Konstruktoren verwenden, die einen Namen oder die EventWaitHandle.OpenExisting Methode angeben.

Weitere Informationen finden Sie im Artikel "EventWaitHandle" . Die API-Referenz finden Sie unter EventWaitHandle, AutoResetEvent, ManualResetEvent, und ManualResetEventSlim.

CountdownEvent-Klasse

Die System.Threading.CountdownEvent Klasse stellt ein Ereignis dar, das festgelegt wird, wenn die Anzahl null ist. Während CountdownEvent.CurrentCount größer als 0 ist, wird ein Thread blockiert, der aufruft CountdownEvent.Wait . Rufen Sie CountdownEvent.Signal auf, um die Anzahl eines Ereignisses zu verringern.

Im Gegensatz zu ManualResetEvent oder ManualResetEventSlim, mit dem Sie die Blockierung mehrerer Threads mit einem Signal von einem Thread aufheben können, können CountdownEvent Sie die Blockierung eines oder mehrerer Threads mit Signalen von mehreren Threads aufheben.

Weitere Informationen finden Sie im CountdownEvent-Artikel und in der CountdownEvent API-Referenz.

Barriereklasse

Die System.Threading.Barrier Klasse stellt eine Threadausführungsbarriere dar. Ein Thread, der die Barrier.SignalAndWait Methode aufruft, signalisiert, dass sie die Barriere erreicht hat, und wartet, bis andere Teilnehmerthreads die Barriere erreichen. Wenn alle teilnehmenden Threads die Barriere erreichen, werden sie weiter ausgeführt, und die Barriere wird zurückgesetzt und kann wieder verwendet werden.

Sie können verwenden Barrier , wenn ein oder mehrere Threads die Ergebnisse anderer Threads erfordern, bevor Sie mit der nächsten Berechnungsphase fortfahren.

Weitere Informationen finden Sie im Artikel "Barrier" und in der Barrier API-Referenz.

Interlocked-Klasse

Die System.Threading.Interlocked Klasse stellt statische Methoden bereit, die einfache atomische Vorgänge für eine Variable ausführen. Zu diesen atomaren Operationen gehören Addition, Inkrementierung und Dekrementierung, Austausch und bedingter Austausch, die auf einem Vergleich basieren, und Lesevorgang eines 64-Bit-Ganzzahlwerts.

Weitere Informationen finden Sie in der Interlocked API-Referenz.

SpinWait-Struktur

Die System.Threading.SpinWait Struktur bietet Unterstützung für Spin-basiertes Warten. Möglicherweise möchten Sie es verwenden, wenn ein Thread darauf warten muss, dass ein Ereignis signalisiert wird oder eine Bedingung erfüllt wird, und die erwartete Wartezeit kürzer ist als die Wartezeit, die mit einem Wartegriff erforderlich wäre oder indem der Thread anderweitig blockiert wird. Mithilfe von SpinWait können Sie einen kurzen Wartezeitraum angeben und danach nur dann auslösen (z. B. durch Warten oder Ruhezustand), wenn die Bedingung nicht in der angegebenen Zeit erfüllt wurde.

Weitere Informationen finden Sie im SpinWait-Artikel und in der SpinWait API-Referenz.

Siehe auch