Partager via


Vue d’ensemble des primitives de synchronisation

.NET fournit une plage de types que vous pouvez utiliser pour synchroniser l’accès à une ressource partagée ou coordonner l’interaction de thread.

Important

Utilisez la même instance primitive de synchronisation pour protéger l’accès d’une ressource partagée. Si vous utilisez différentes instances primitives de synchronisation pour protéger la même ressource, vous contournerez la protection fournie par une primitive de synchronisation.

Classe WaitHandle et types de synchronisation légers

Plusieurs primitives de synchronisation .NET dérivent de la System.Threading.WaitHandle classe, qui encapsule un handle de synchronisation de système d’exploitation natif et utilise un mécanisme de signalisation pour l’interaction de thread. Ces classes sont les suivantes :

  • System.Threading.Mutex, qui accorde un accès exclusif à une ressource partagée. L’état d’un mutex est signalé si aucun thread ne le possède.
  • System.Threading.Semaphore, qui limite le nombre de threads pouvant accéder simultanément à une ressource partagée ou à un pool de ressources. L’état d’un sémaphore est défini sur signalé lorsque son nombre est supérieur à zéro et non signé lorsque son nombre est égal à zéro.
  • System.Threading.EventWaitHandle, qui représente un événement de synchronisation de threads et peut être dans un état signalé ou non signé.
  • System.Threading.AutoResetEvent, qui dérive et EventWaitHandle , lorsqu’il est signalé, réinitialise automatiquement à un état non signé après avoir libéré un thread en attente unique.
  • System.Threading.ManualResetEvent, qui dérive et EventWaitHandle , lorsqu’il est signalé, reste dans un état signalé jusqu’à ce que la Reset méthode soit appelée.

Dans .NET Framework, car WaitHandle dérive de System.MarshalByRefObject, ces types peuvent être utilisés pour synchroniser les activités des threads entre les limites du domaine d’application.

Dans .NET Framework, .NET Core et .NET 5+, certains de ces types peuvent représenter des handles de synchronisation système nommés, visibles dans tout le système d’exploitation et pouvant être utilisés pour la synchronisation entre processus :

Pour plus d’informations, consultez la référence de l’API WaitHandle .

Les types de synchronisation légers ne reposent pas sur les handles de système d’exploitation sous-jacents et fournissent généralement de meilleures performances. Toutefois, elles ne peuvent pas être utilisées pour la synchronisation entre processus. Utilisez ces types pour la synchronisation de threads au sein d’une application.

Certains de ces types sont des alternatives aux types dérivés de WaitHandle. Par exemple, SemaphoreSlim est une alternative légère à Semaphore.

Synchronisation de l’accès à une ressource partagée

.NET fournit une plage de primitives de synchronisation pour contrôler l’accès à une ressource partagée par plusieurs threads.

Classe Monitor

La System.Threading.Monitor classe accorde un accès mutuellement exclusif à une ressource partagée en acquérant ou en libérant un verrou sur l’objet qui identifie la ressource. Pendant qu’un verrou est conservé, le thread qui contient le verrou peut à nouveau acquérir et libérer le verrou. Tout autre thread est bloqué pour acquérir le verrou et la Monitor.Enter méthode attend que le verrou soit libéré. La Enter méthode acquiert un verrou libéré. Vous pouvez également utiliser la Monitor.TryEnter méthode pour spécifier la durée pendant laquelle un thread tente d’acquérir un verrou. Étant donné que la classe a une Monitor affinité de thread, le thread qui a acquis un verrou doit libérer le verrou en appelant la Monitor.Exit méthode.

Vous pouvez coordonner l’interaction des threads qui acquièrent un verrou sur le même objet à l’aide des méthodes et Monitor.PulseAll des Monitor.WaitméthodesMonitor.Pulse.

Pour plus d’informations, consultez la référence de l’API Monitor .

Remarque

Utilisez l’instruction lock en C# et l’instruction SyncLock dans Visual Basic pour synchroniser l’accès à une ressource partagée au lieu d’utiliser la Monitor classe directement. Ces instructions sont implémentées à l’aide des Enter méthodes et Exit d’un try…finally bloc pour s’assurer que le verrou acquis est toujours libéré.

Mutex, classe

La System.Threading.Mutex classe, par exemple Monitor, accorde un accès exclusif à une ressource partagée. Utilisez l’une des surcharges de méthode Mutex.WaitOne pour demander la propriété d’un mutex. Comme Monitor, Mutex a une affinité de thread et le thread qui a acquis un mutex doit le libérer en appelant la Mutex.ReleaseMutex méthode.

Contrairement Monitorà , la Mutex classe peut être utilisée pour la synchronisation entre processus. Pour ce faire, utilisez un mutex nommé, qui est visible dans tout le système d’exploitation. Pour créer une instance mutex nommée, utilisez un constructeur Mutex qui spécifie un nom. Vous pouvez également appeler la Mutex.OpenExisting méthode pour ouvrir un mutex système nommé existant.

Pour plus d’informations, consultez l’article Mutexes et la référence de l’API Mutex .

Structure SpinLock

La System.Threading.SpinLock structure, par exemple Monitor, accorde un accès exclusif à une ressource partagée en fonction de la disponibilité d’un verrou. Lorsque SpinLock vous tentez d’acquérir un verrou qui n’est pas disponible, il attend dans une boucle, en vérifiant à plusieurs reprises jusqu’à ce que le verrou soit disponible.

Pour plus d’informations sur les avantages et les inconvénients de l’utilisation du verrou de rotation, consultez l’article SpinLock et la référence de l’API SpinLock .

Classe ReaderWriterLockSlim

La System.Threading.ReaderWriterLockSlim classe accorde un accès exclusif à une ressource partagée pour l’écriture et permet à plusieurs threads d’accéder simultanément à la ressource pour la lecture. Vous pouvez utiliser ReaderWriterLockSlim pour synchroniser l’accès à une structure de données partagée qui prend en charge les opérations de lecture thread-safe, mais nécessite un accès exclusif pour effectuer une opération d’écriture. Lorsqu’un thread demande un accès exclusif (par exemple, en appelant la ReaderWriterLockSlim.EnterWriteLock méthode), les demandes de lecteur et d’enregistreur suivantes bloquent jusqu’à ce que tous les lecteurs existants aient quitté le verrou, et que l’enregistreur a entré et quitté le verrou.

Pour plus d’informations, consultez la référence de l’API ReaderWriterLockSlim .

Classes sémaphore et sémaphoreSlim

Les System.Threading.Semaphore classes et System.Threading.SemaphoreSlim les classes limitent le nombre de threads qui peuvent accéder à une ressource partagée ou à un pool de ressources simultanément. Des threads supplémentaires qui demandent la ressource attendent que n’importe quel thread libère le sémaphore. Étant donné que le sémaphore n’a pas d’affinité de thread, un thread peut acquérir le sémaphore et un autre peut le libérer.

SemaphoreSlim est une alternative légère et Semaphore ne peut être utilisée que pour la synchronisation dans une limite de processus unique.

Sur Windows, vous pouvez utiliser Semaphore pour la synchronisation entre processus. Pour ce faire, créez une Semaphore instance qui représente un sémaphore système nommé à l’aide de l’un des constructeurs sémaphores qui spécifient un nom ou la Semaphore.OpenExisting méthode. SemaphoreSlim ne prend pas en charge les sémaphores système nommés.

Pour plus d’informations, consultez l’article Semaphore et SemaphoreSlim et la référence de l’API SemaphoreSemaphoreSlim .

Interaction des threads ou signalisation

L’interaction de thread (ou la signalisation de thread) signifie qu’un thread doit attendre la notification, ou un signal, à partir d’un ou plusieurs threads afin de continuer. Par exemple, si le thread A appelle la Thread.Join méthode du thread B, le thread A est bloqué jusqu’à ce que le thread B se termine. Les primitives de synchronisation décrites dans la section précédente fournissent un mécanisme différent pour la signalisation : en libérant un verrou, un thread avertit un autre thread qu’il peut continuer en acquérant le verrou.

Cette section décrit les constructions de signalisation supplémentaires fournies par .NET.

Classes EventWaitHandle, AutoResetEvent, ManualResetEvent et ManualResetEventSlim

La System.Threading.EventWaitHandle classe représente un événement de synchronisation de threads.

Un événement de synchronisation peut être dans un état non signé ou signalé. Lorsque l’état d’un événement n’est pas signé, un thread qui appelle la surcharge de WaitOne l’événement est bloqué jusqu’à ce qu’un événement soit signalé. La EventWaitHandle.Set méthode définit l’état d’un événement à signaler.

Le comportement d’un EventWaitHandle signal signalé dépend de son mode de réinitialisation :

Sur Windows, vous pouvez utiliser EventWaitHandle pour la synchronisation entre processus. Pour ce faire, créez une EventWaitHandle instance qui représente un événement de synchronisation système nommé à l’aide de l’un des constructeurs EventWaitHandle qui spécifie un nom ou la EventWaitHandle.OpenExisting méthode.

Pour plus d’informations, consultez l’article EventWaitHandle . Pour obtenir la référence de l’API, consultez EventWaitHandle, , AutoResetEventManualResetEventet ManualResetEventSlim.

CountdownEvent, classe

La System.Threading.CountdownEvent classe représente un événement qui devient défini lorsque son nombre est égal à zéro. Bien qu’il CountdownEvent.CurrentCount soit supérieur à zéro, un thread qui appelle CountdownEvent.Wait est bloqué. Appelez CountdownEvent.Signal à décrémenter le nombre d’événements.

Contrairement à ManualResetEvent ou ManualResetEventSlim, que vous pouvez utiliser pour débloquer plusieurs threads avec un signal à partir d’un thread, vous pouvez utiliser CountdownEvent pour débloquer un ou plusieurs threads avec des signaux provenant de plusieurs threads.

Pour plus d’informations, consultez l’article CountdownEvent et la référence de l’API CountdownEvent .

Classe Barrière

La System.Threading.Barrier classe représente une barrière d’exécution de thread. Thread qui appelle la Barrier.SignalAndWait méthode signale qu’elle a atteint la barrière et attend que d’autres threads participants atteignent la barrière. Lorsque tous les threads participants atteignent la barrière, ils continuent et la barrière est réinitialisée et peut être utilisée à nouveau.

Vous pouvez utiliser Barrier quand un ou plusieurs threads nécessitent les résultats d’autres threads avant de passer à la phase de calcul suivante.

Pour plus d’informations, consultez l’article Barrière et la référence de l’API Barrier .

Classe interblocée

La System.Threading.Interlocked classe fournit des méthodes statiques qui effectuent des opérations atomiques simples sur une variable. Ces opérations atomiques incluent l’ajout, l’incrémentation et la décrémentation, l’échange et l’échange conditionnel qui dépend d’une comparaison et d’une opération de lecture d’une valeur entière 64 bits.

Pour plus d’informations, consultez la référence de l’API Interlocked .

Structure SpinWait

La System.Threading.SpinWait structure prend en charge l’attente basée sur les spins. Vous souhaiterez peut-être l’utiliser lorsqu’un thread doit attendre qu’un événement soit signalé ou qu’une condition soit remplie, mais lorsque le temps d’attente réel est censé être inférieur au temps d’attente requis à l’aide d’un handle d’attente ou en bloquant le thread. En utilisant SpinWait, vous pouvez spécifier une courte période de temps à tourner pendant l’attente, puis générer (par exemple, en attendant ou en veille) uniquement si la condition n’a pas été remplie dans l’heure spécifiée.

Pour plus d’informations, consultez l’article SpinWait et la référence de l’API SpinWait .

Voir aussi