Mes deux cents sur Mutex et Semaphore en C #

La synchronisation des threads est utilisée pour empêcher plusieurs threads d'accéder simultanément à une ressource partagée. Mutex et Semaphore sont deux des concepts liés les plus importants. Comprenons quels sont ces deux éléments et quand devrions-nous les utiliser.

Avant de commencer notre discussion, examinons rapidement les concepts de base. Un thread est la plus petite unité d'exécution d'un processus. Essentiellement, le multi-threading vous aide à effectuer plusieurs tâches simultanément et donc à augmenter le débit global de l'application.

Un Mutex est une primitive de synchronisation qui peut fonctionner sur plusieurs processus, c'est-à-dire qu'elle peut être utilisée pour la synchronisation inter-processus. Un sémaphore au contraire est celui qui vous permet de limiter le nombre de threads qui ont accès à une ressource partagée au même moment. En substance, un sémaphore est une forme plus généralisée d'un Mutex.

Un sémaphore est utilisé pour limiter le nombre de threads pouvant accéder simultanément à une ressource partagée. Essentiellement, il est utilisé pour limiter simultanément le nombre de consommateurs pour une ressource partagée particulière. Vous pouvez profiter de Semaphore pour implémenter un verrouillage non exclusif et donc limiter la concurrence.

Notez qu'un Mutex est utilisé pour le verrouillage exclusif sur une ressource partagée. En d'autres termes, un Mutex vous permet d'acquérir un verrou mutuellement exclusif - n'importe quel thread aurait accès à une ressource partagée à un moment donné. Le verrouillage exclusif est utilisé pour garantir qu'à tout moment donné, un et un seul thread peut entrer dans une section critique. Une section critique peut être définie comme une structure de données ou une ressource partagée par plusieurs threads, mais un et un seul thread peut y avoir accès à tout moment.

La classe System.Threading.Mutex représente un Mutex et la classe System.Threading.Semaphore est utilisée pour travailler avec les sémaphores. Vous pouvez utiliser la méthode WaitOne sur une instance de la classe Mutex pour verrouiller et utiliser la méthode ReleaseMutex pour déverrouiller.

Mutex mutexObject = new Mutex(false, "Demo");

if (!mutexObject.WaitOne(TimeSpan.FromSeconds(10), false))

     {

             Console.WriteLine("Quitting for now as another instance is in execution...");

               return;

     }

Pour créer un sémaphore en C #, vous devez créer une instance de la classe Semaphore. Lors de la création d'une instance Semaphore, vous devez passer deux arguments à son constructeur d'arguments. Alors que le premier argument est utilisé pour indiquer le nombre d'entrées de ressources initiales, le second argument est utilisé pour spécifier le nombre maximal d'entrées de ressources simultanées. Notez que si vous souhaitez réserver tous les emplacements pour les nouveaux threads qui seront créés, vous devez spécifier des valeurs identiques pour ces deux paramètres. L'extrait de code suivant illustre comment vous pouvez créer un sémaphore en C #.

public static Semaphore threadPool = new Semaphore(3, 5);

Reportez-vous à l'extrait de code ci-dessus. L'instruction ci-dessus crée un objet sémaphore nommé threadPool qui peut prendre en charge un maximum de 5 requêtes simultanées. Notez que le nombre initial est défini sur 3 comme indiqué dans le premier paramètre du constructeur. Cela implique que 2 emplacements sont réservés pour le thread actuel et 3 emplacements sont disponibles pour les autres threads. Écrivons maintenant du code!

L'extrait de code suivant montre comment vous pouvez créer et démarrer 10 threads à l'aide de la classe Thread disponible dans l'espace de noms System.Threading. Notez comment le délégué ThreadStart a été utilisé.

for (int i = 0; i < 10; i++)

{

   Thread threadObject = new Thread(new ThreadStart(PerformSomeWork));

   threadObject.Name = "Thread Name: " + i;

   threadObject.Start();

}

Voici le code de la méthode PerformSomeWork. C'est la méthode qui contient en fait le code pour travailler avec les sémaphores.

private static void PerformSomeWork()

       {

           threadPool.WaitOne();

           Console.WriteLine("Thread {0} is inside the critical section...", Thread.CurrentThread.Name);

           Thread.Sleep(10000);

           threadPool.Release();

       }

Reportez-vous à la méthode PerformSomeWork donnée ci-dessus. La méthode WaitOne est appelée sur l'instance Semaphore pour bloquer le thread actuel jusqu'à ce qu'un signal soit reçu. La méthode Release est appelée sur la même instance pour libérer le sémaphore. Voici la liste complète des codes pour votre référence.

class SemaphoreDemo

   {

       public static Semaphore threadPool = new Semaphore(3, 5);

       public static void Main(string[] args)

       {

           for (int i = 0; i < 10; i++)

           {

               Thread threadObject = new Thread(new ThreadStart(PerformSomeWork));

               threadObject.Name = "Thread Name: " + i;

               threadObject.Start();

           }

           Console.ReadLine();

       }

       private static void PerformSomeWork()

       {

           threadPool.WaitOne();

           Console.WriteLine("Thread {0} is inside the critical section...", Thread.CurrentThread.Name);

           Thread.Sleep(10000);

           threadPool.Release();

       }

   }