Mis dos centavos en Mutex y Semaphore en C #

La sincronización de subprocesos se utiliza para evitar que varios subprocesos accedan a un recurso compartido al mismo tiempo. Mutex y Semaphore son dos de los conceptos relacionados más importantes. Entendamos qué son ambos y cuándo deberíamos usarlos.

Antes de comenzar nuestra discusión, echemos un vistazo rápido a los conceptos básicos. Un hilo es la unidad de ejecución más pequeña dentro de un proceso. Básicamente, el subproceso múltiple lo ayuda a realizar varias tareas simultáneamente y, por lo tanto, aumenta el rendimiento general de la aplicación.

Un Mutex es una primitiva de sincronización que puede funcionar en todos los procesos, es decir, se puede utilizar para la sincronización entre procesos. Un semáforo, por el contrario, es uno que le permite limitar el número de subprocesos que tienen acceso a un recurso compartido en el mismo momento. En esencia, un semáforo es una forma más generalizada de mutex.

Un semáforo se utiliza para limitar la cantidad de subprocesos que pueden tener acceso a un recurso compartido al mismo tiempo. En esencia, se utiliza para limitar el número de consumidores de un recurso compartido en particular al mismo tiempo. Puede aprovechar Semaphore para implementar un bloqueo no exclusivo y, por lo tanto, limitar la concurrencia.

Tenga en cuenta que un mutex se utiliza para el bloqueo exclusivo de un recurso compartido. En otras palabras, un Mutex le permite adquirir un bloqueo mutuamente exclusivo: cualquier hilo tendría acceso a un recurso compartido en un momento dado. El bloqueo exclusivo se utiliza para garantizar que en un momento dado, uno y solo un hilo pueda entrar en una sección crítica. Una sección crítica puede definirse como una estructura de datos o un recurso compartido por varios subprocesos, pero uno y solo un subproceso puede tener acceso a él en un momento dado.

La clase System.Threading.Mutex representa un Mutex y la clase System.Threading.Semaphore se utiliza para trabajar con Semaphores. Puede usar el método WaitOne en una instancia de la clase Mutex para bloquear y usar el método ReleaseMutex para desbloquear.

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;

     }

Para crear un semáforo en C #, debe crear una instancia de la clase Semaphore. Al crear una instancia de Semaphore, debe pasar dos argumentos a su constructor de argumentos. Mientras que el primer argumento se usa para indicar el número de entradas de recursos iniciales, el segundo argumento se usa para especificar el número máximo de entradas de recursos concurrentes. Tenga en cuenta que si desea reservar todos los espacios para los nuevos subprocesos que se crearán, debe especificar valores idénticos para ambos parámetros. El siguiente fragmento de código ilustra cómo puede crear un semáforo en C #.

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

Consulte el fragmento de código proporcionado anteriormente. La declaración anterior crea un objeto semáforo llamado threadPool que puede admitir un máximo de 5 solicitudes simultáneas. Tenga en cuenta que el recuento inicial se establece en 3 como se indica en el primer parámetro del constructor. Esto implica que se reservan 2 ranuras para el subproceso actual y 3 ranuras están disponibles para otros subprocesos. ¡Ahora escribamos un código!

El siguiente fragmento de código muestra cómo puede crear e iniciar 10 subprocesos utilizando la clase Thread disponible en el espacio de nombres System.Threading. Observe cómo se ha utilizado el delegado de ThreadStart.

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

{

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

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

   threadObject.Start();

}

Aquí está el código del método PerformSomeWork. Este es el método que realmente contiene el código para trabajar con semáforos.

private static void PerformSomeWork()

       {

           threadPool.WaitOne();

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

           Thread.Sleep(10000);

           threadPool.Release();

       }

Consulte el método PerformSomeWork proporcionado anteriormente. El método WaitOne se llama en la instancia de Semaphore para bloquear el hilo actual hasta que se recibe una señal. El método Release se llama en la misma instancia para liberar el semáforo. Aquí está la lista completa de códigos para su referencia.

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();

       }

   }