Gegevens synchroniseren voor multithreading
Wanneer meerdere threads de eigenschappen en methoden van één object kunnen aanroepen, is het essentieel dat deze aanroepen worden gesynchroniseerd. Anders kan één thread onderbreken wat een andere thread doet en kan het object een ongeldige status hebben. Een klasse waarvan de leden worden beschermd tegen dergelijke onderbrekingen, wordt thread-safe genoemd.
.NET biedt verschillende strategieën voor het synchroniseren van toegang tot instanties en statische leden.
Gesynchroniseerde coderegio's. U kunt de Monitor-klasse- of compilerondersteuning voor deze klasse gebruiken om alleen het codeblok te synchroniseren dat dit nodig heeft, waardoor de prestaties worden verbeterd.
Handmatige synchronisatie. U kunt de synchronisatieobjecten van de .NET-klassebibliotheek gebruiken. Zie Overzicht van synchronisatieprimitieven, waaronder een bespreking van de Monitor klasse.
Gesynchroniseerde contexten. Alleen voor .NET Framework-toepassingen kunt u de SynchronizationAttribute gebruiken om eenvoudige, automatische synchronisatie in te schakelen voor ContextBoundObject-objecten.
Verzamelingsklassen in de System.Collections.Concurrent-naamruimte. Deze klassen bieden ingebouwde gesynchroniseerde bewerkingen voor toevoegen en verwijderen. Zie Thread-Safe Verzamelingenvoor meer informatie.
De common language runtime biedt een threadmodel waarin klassen tot een aantal categorieën behoren die op verschillende manieren gesynchroniseerd kunnen worden, op basis van de vereisten. In de volgende tabel ziet u welke synchronisatieondersteuning wordt geboden voor velden en methoden met een bepaalde synchronisatiecategorie.
Categorie | Globale velden | Statische velden | Statische methoden | Instancevelden | Instancemethoden | Specifieke codeblokken |
---|---|---|---|---|---|---|
Geen synchronisatie | Nee | Nee | Nee | Nee | Nee | Nee |
Gesynchroniseerde context | Nee | Nee | Nee | Ja | Ja | Nee |
Gesynchroniseerde coderegio's | Nee | Nee | Alleen als deze optie is gemarkeerd | Nee | Alleen als deze optie is gemarkeerd | Alleen als deze optie is gemarkeerd |
Handmatige synchronisatie | Handmatig | Handmatig | Handmatig | Handmatig | Handmatig | Handmatig |
Geen synchronisatie
Dit is de standaardwaarde voor objecten. Elke thread heeft op elk gewenst moment toegang tot elke methode of elk veld. Slechts één thread tegelijk moet toegang krijgen tot deze objecten.
Handmatige synchronisatie
De .NET-klassebibliotheek biedt een aantal klassen voor het synchroniseren van threads. Zie Overzicht van synchronisatieprimitieven.
Gesynchroniseerde coderegio's
U kunt de Monitor-klasse of een trefwoord compiler gebruiken om codeblokken, instantiemethoden en statische methoden te synchroniseren. Er is geen ondersteuning voor gesynchroniseerde statische velden.
Visual Basic en C# ondersteunen het markeren van codeblokken met een bepaald taalwoord, de lock
-instructie in C# of de SyncLock
-instructie in Visual Basic. Wanneer de code wordt uitgevoerd door een thread, wordt geprobeerd de vergrendeling te verkrijgen. Wanneer het slot al is verkregen door een andere thread, blokkeert de thread totdat het slot beschikbaar is. Wanneer de thread het gesynchroniseerde codeblok verlaat, wordt de vergrendeling vrijgegeven, ongeacht hoe de thread het blok verlaat.
Notitie
Vanaf C# 13 herkent de lock
instructie of het vergrendelde object een exemplaar van System.Threading.Lock is en de EnterScope
methode gebruikt om een gesynchroniseerde regio te maken. De lock
, wanneer het doel geen Lock
exemplaar is en SyncLock
instructies worden geïmplementeerd met behulp van Monitor.Enter en Monitor.Exit, zodat andere methoden van Monitor kunnen worden gebruikt in combinatie met deze in de gesynchroniseerde regio.
U kunt een methode ook versieren met een MethodImplAttribute met een waarde van MethodImplOptions.Synchronized, die hetzelfde effect heeft als het gebruik van Monitor of een van de compilertrefwoorden om de hele hoofdtekst van de methode te vergrendelen.
Thread.Interrupt kan worden gebruikt om een thread te doorbreken uit blokkerende operaties zoals wachten op toegang tot een gesynchroniseerd deel van de code. Thread.Interrupt wordt ook gebruikt om threads uit bewerkingen te breken, zoals Thread.Sleep.
Belangrijk
Vergrendel het type niet — dat wil zeggen, typeof(MyType)
in C#, GetType(MyType)
in Visual Basic, of MyType::typeid
in C++ — om static
methoden (Shared
methoden in Visual Basic) te beveiligen. Gebruik in plaats daarvan een privé statisch object. Gebruik op dezelfde manier geen this
in C# (Me
in Visual Basic) om exemplaarmethoden te vergrendelen. Gebruik in plaats daarvan een privéobject. Een klasse of exemplaar kan worden vergrendeld door andere code dan uw eigen code, waardoor mogelijk impasses of prestatieproblemen optreden.
Compilerondersteuning
Visual Basic en C# ondersteunen een taalwoord dat gebruikmaakt van Monitor.Enter en Monitor.Exit om het object te vergrendelen. Visual Basic ondersteunt de instructie SyncLock; C# ondersteunt de instructie vergrendelen.
Als er in beide gevallen een uitzondering wordt gegenereerd in het codeblok, wordt de vergrendeling die is verkregen door de vergrendeling of SyncLock- automatisch vrijgegeven. De C#- en Visual Basic-compilers verzenden een /ten slotte blok met Monitor.Enter- aan het begin van de poging en Monitor.Exit in het ten slotte blok. Als er een uitzondering optreedt in het vergrendelingsblok of SyncLock blok, wordt de finally afhandelaar uitgevoerd, zodat u eventuele opschoningswerkzaamheden kunt uitvoeren.
Gesynchroniseerde context
In .NET Framework-toepassingen kunt u de SynchronizationAttribute op elke ContextBoundObject gebruiken om alle exemplaarmethoden en -velden te synchroniseren. Alle objecten in hetzelfde contextdomein delen dezelfde vergrendeling. Meerdere threads hebben toegang tot de methoden en velden, maar er is maar één thread tegelijk toegestaan.