Remarque
L’accès à cette page requiert une autorisation. Vous pouvez essayer de vous connecter ou de modifier des répertoires.
L’accès à cette page requiert une autorisation. Vous pouvez essayer de modifier des répertoires.
.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.
Importante
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 est dérivé de EventWaitHandle et, quand il est signalé, se réinitialise automatiquement à un état non signalé après avoir libéré un seul thread en attente.
- System.Threading.ManualResetEvent, qui dérive de EventWaitHandle et, lorsqu’il est signalé, reste dans un état signalé jusqu’à ce que la méthode Reset 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 :
- Mutex
- Semaphore (sur Windows)
- EventWaitHandle (sur Windows)
Pour plus d’informations, consultez la référence de l’API WaitHandle .
Les types de synchronisation légers ne s’appuient pas sur les descripteurs 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.
Monitor (classe)
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. Tant qu’un verrou est maintenu, le thread qui contient le verrou peut à nouveau obtenir et libérer le verrou. Tout autre thread est bloqué lors de l'acquisition du verrou et la méthode Monitor.Enter 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 affinité de thread Monitor, le thread qui a acquis un verrou doit libérer le verrou en appelant la méthode Monitor.Exit.
Vous pouvez coordonner l’interaction des threads qui acquièrent un verrou sur le même objet à l’aide des méthodes Monitor.Wait, Monitor.Pulse, et Monitor.PulseAll.
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 méthodes Enter et Exit, ainsi que d’un bloc try…finally, pour s’assurer que le verrou acquis est toujours libéré.
Classe Mutex
La System.Threading.Mutex classe, par exemple Monitor, accorde un accès exclusif à une ressource partagée. Utilisez une des surcharges de méthode Mutex.WaitOne pour demander la propriété d’un mutex. Comme Monitor, Mutex a une affinité de fil et le fil qui a acquis un mutex doit le libérer en appelant la méthode Mutex.ReleaseMutex.
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 méthode Mutex.OpenExisting pour ouvrir un mutex de 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 tente d’acquérir un verrou qui n’est pas disponible, il est conservé dans une boucle et effectue des vérifications à plusieurs reprises jusqu'à ce que le verrou devienne 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 méthode ReaderWriterLockSlim.EnterWriteLock), les demandes de lecteur et d’écrivain suivantes sont bloquées jusqu’à ce que tous les lecteurs existants aient quitté le blocage, et que l’écrivain soit entré et sorti du blocage.
Pour plus d’informations, consultez la référence de l’API ReaderWriterLockSlim .
Classes Semaphore et SemaphoreSlim
Les classes System.Threading.Semaphore et System.Threading.SemaphoreSlim limitent le nombre de threads qui peuvent accéder à une ressource partagée ou à un pool de ressources concurremment. 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 à Semaphore et ne peut être utilisée que pour la synchronisation dans les limites d'un seul processus.
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 de systèmes 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 signalé, un thread qui appelle la surcharge WaitOne de 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 qui a été signalé dépend de son mode de réinitialisation :
- Un EventWaitHandle créé avec l’indicateur EventResetMode.AutoReset se réinitialise automatiquement après avoir libéré un seul thread en attente. C'est comme un tourniquet qui ne laisse passer qu'un seul thread à chaque fois qu'il est signalé. La System.Threading.AutoResetEvent classe, qui dérive de EventWaitHandle, représente ce comportement.
- Un EventWaitHandle créé avec l'indicateur EventResetMode.ManualReset reste activé jusqu'à ce que sa méthode Reset soit appelée. C’est comme une porte fermée jusqu’à ce qu’elle soit signalée, puis reste ouverte jusqu’à ce que quelqu’un le ferme. La System.Threading.ManualResetEvent classe, qui dérive de EventWaitHandle, représente ce comportement. La System.Threading.ManualResetEventSlim classe est une alternative légère à ManualResetEvent.
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.
Classe CountdownEvent
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 pour 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 verrouillé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 .
La structure SpinWait
La structure System.Threading.SpinWait 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. À l'aide de SpinWait, vous pouvez spécifier une courte période de rotation pendant l'attente, puis générer (par exemple, en attente ou en veille) uniquement si la condition n'a pas été remplie dans le délai spécifié.
Pour plus d’informations, consultez l’article SpinWait et la référence de l’API SpinWait .