Partager via


Sémaphore et SemaphoreSlim

La System.Threading.Semaphore classe représente un sémaphore nommé (à l’échelle du système) ou local. Il s’agit d’un wrapper mince autour de l’objet sémaphore Win32. Les sémaphores Win32 sont des sémaphores de comptage, qui peuvent être utilisés pour contrôler l’accès à un pool de ressources.

La SemaphoreSlim classe représente un sémaphore léger et rapide qui peut être utilisé pour attendre dans un seul processus lorsque les temps d’attente sont censés être très courts. SemaphoreSlim s’appuie autant que possible sur les primitives de synchronisation fournies par le Common Language Runtime (CLR). Toutefois, il fournit également des handles d'attente initialisés tardivement et basés sur le noyau qui permettent l'attente de plusieurs sémaphores. SemaphoreSlim prend également en charge l'utilisation de jetons d'annulation, mais il ne prend pas en charge les sémaphores nommés ni l'utilisation d'un handle d'attente pour la synchronisation.

Gestion d’une ressource limitée

Les threads entrent dans le sémaphore en appelant la WaitOne méthode, héritée de la WaitHandle classe, dans le cas d’un System.Threading.Semaphore objet ou de la SemaphoreSlim.WaitSemaphoreSlim.WaitAsync méthode, dans le cas d’un SemaphoreSlim objet. Quand l'appel est retourné, le nombre du sémaphore est décrémenté. Lorsqu’un thread demande une entrée et que le nombre est égal à zéro, le thread est bloqué. À mesure que les threads libèrent le sémaphore en appelant la méthode Semaphore.Release ou SemaphoreSlim.Release, les threads bloqués sont autorisés à entrer. Il n’existe aucun ordre garanti, tel que le premier entré, le premier sorti (FIFO) ou le dernier entré, le premier sorti (LIFO), pour que les threads bloqués entrent dans le sémaphore.

Un thread peut entrer dans le sémaphore plusieurs fois en appelant la méthode de l’objet System.Threading.SemaphoreWaitOne ou la méthode de l’objet SemaphoreSlimWait à plusieurs reprises. Pour libérer le sémaphore, le thread peut soit appeler la surcharge de méthode Semaphore.Release() ou SemaphoreSlim.Release() le même nombre de fois, soit appeler la surcharge de méthode Semaphore.Release(Int32) ou SemaphoreSlim.Release(Int32) et spécifier le nombre d’entrées à libérer.

Sémaphores et identité de thread

Les deux types de sémaphores n’imposent pas l’identité de thread lors des appels aux méthodes WaitOne, Wait, Release, et SemaphoreSlim.Release. Par exemple, un scénario classique d'utilisation des sémaphores implique un thread producteur et un thread consommateur, avec un thread incrémentant le nombre du sémaphore et l'autre le décrémentant.

Il incombe au programmeur de s’assurer qu’un thread ne libère pas le sémaphore trop souvent. Par exemple, supposons qu’un sémaphore a un nombre maximal de deux, et que le thread A et le thread B entrent tous les deux dans le sémaphore. Si une erreur de programmation dans le thread B le conduit à appeler Release deux fois, les deux appels réussissent. Le nombre maximal du sémaphore sera alors atteint, et quand le thread A appellera Release, une exception SemaphoreFullException sera levée.

Sémaphores nommés

Le système d’exploitation Windows permet aux sémaphores d’avoir des noms. Un sémaphore nommé est disponible à l'échelle du système. C'est-à-dire qu'une fois créé, le sémaphore nommé est visible par tous les threads de tous les processus. Par conséquent, le sémaphore nommé peut être utilisé pour synchroniser les activités des processus ainsi que les threads.

Vous pouvez créer un Semaphore objet qui représente un sémaphore système nommé à l’aide de l’un des constructeurs qui spécifie un nom.

Remarque

Étant donné que les sémaphores nommés sont à l’échelle du système, il est possible d’avoir plusieurs Semaphore objets qui représentent le même sémaphore nommé. Chaque fois que vous appelez un constructeur ou la Semaphore.OpenExisting méthode, un nouvel Semaphore objet est créé. La spécification du même nom crée plusieurs objets qui représentent le même sémaphore nommé.

Soyez prudent lorsque vous utilisez des sémaphores nommés. Comme ils sont à l’échelle du système, un autre processus qui utilise le même nom peut accéder à votre sémaphore de manière inattendue. Le code malveillant s’exécutant sur le même ordinateur peut l’utiliser comme base d’une attaque par déni de service.

Utilisez la sécurité du contrôle d’accès pour protéger un Semaphore objet qui représente un sémaphore nommé, de préférence à l’aide d’un constructeur qui spécifie un System.Security.AccessControl.SemaphoreSecurity objet. Vous pouvez également appliquer la sécurité du contrôle d’accès à l’aide de la Semaphore.SetAccessControl méthode, mais cela laisse une fenêtre de vulnérabilité entre le moment où le sémaphore est créé et le moment où il est protégé. La protection des sémaphores grâce à la sécurité de contrôle d'accès empêche les attaques malveillantes, mais ne résout pas le problème des conflits de noms involontaires.

Voir aussi