Solución productor-consumidor utilizando semáforos en Java | conjunto 2

Requisitos previos: semáforo en Java , comunicación entre procesos , problema del consumidor productor con semáforos | Serie 1

En informática, el problema del productor-consumidor (también conocido como problema del búfer acotado) es un ejemplo clásico de un problema de sincronización de procesos múltiples. El problema describe dos procesos, el productor y el consumidor, que comparten un búfer común de tamaño fijo que se utiliza como cola.

  • El trabajo del productor es generar datos, ponerlos en el búfer y comenzar de nuevo.
  • Al mismo tiempo, el consumidor consume los datos (es decir, los elimina del búfer), una pieza a la vez.

Problema: para asegurarse de que el productor no intente agregar datos en el búfer si está lleno y que el consumidor no intente eliminar datos de un búfer vacío.

Solución: el productor debe ir a dormir o descartar datos si el búfer está lleno. La próxima vez que el consumidor retire un artículo del búfer, notifica al productor, quien comienza a llenar el búfer nuevamente. De la misma manera, el consumidor puede irse a dormir si encuentra que el búfer está vacío. La próxima vez que el productor pone datos en el búfer, despierta al consumidor dormido.
Una solución inadecuada podría resultar en un punto muerto en el que ambos procesos esperan ser activados.

En la solución posterior al Productor-Consumidor que usa subprocesos en Java, hemos discutido la solución anterior mediante el uso de comunicación entre subprocesos (esperar(), notificar(), dormir()). En esta publicación, usaremos semáforos para implementar lo mismo.

La siguiente solución consta de cuatro clases:

  1. P : la cola que está intentando sincronizar
  2. Productor: el objeto enstringdo que produce entradas de cola
  3. Consumidor: el objeto subproceso que consume entradas de la cola
  4. PC: la clase de controlador que crea el único Q, productor y consumidor.
// Java implementation of a producer and consumer
// that use semaphores to control synchronization.
  
import java.util.concurrent.Semaphore;
  
class Q {
    // an item
    int item;
  
    // semCon initialized with 0 permits
    // to ensure put() executes first
    static Semaphore semCon = new Semaphore(0);
  
    static Semaphore semProd = new Semaphore(1);
  
    // to get an item from buffer
    void get()
    {
        try {
            // Before consumer can consume an item,
            // it must acquire a permit from semCon
            semCon.acquire();
        }
        catch (InterruptedException e) {
            System.out.println("InterruptedException caught");
        }
  
        // consumer consuming an item
        System.out.println("Consumer consumed item : " + item);
  
        // After consumer consumes the item,
        // it releases semProd to notify producer
        semProd.release();
    }
  
    // to put an item in buffer
    void put(int item)
    {
        try {
            // Before producer can produce an item,
            // it must acquire a permit from semProd
            semProd.acquire();
        }
        catch (InterruptedException e) {
            System.out.println("InterruptedException caught");
        }
  
        // producer producing an item
        this.item = item;
  
        System.out.println("Producer produced item : " + item);
  
        // After producer produces the item,
        // it releases semCon to notify consumer
        semCon.release();
    }
}
  
// Producer class
class Producer implements Runnable {
    Q q;
    Producer(Q q)
    {
        this.q = q;
        new Thread(this, "Producer").start();
    }
  
    public void run()
    {
        for (int i = 0; i < 5; i++)
            // producer put items
            q.put(i);
    }
}
  
// Consumer class
class Consumer implements Runnable {
    Q q;
    Consumer(Q q)
    {
        this.q = q;
        new Thread(this, "Consumer").start();
    }
  
    public void run()
    {
        for (int i = 0; i < 5; i++)
            // consumer get items
            q.get();
    }
}
  
// Driver class
class PC {
    public static void main(String args[])
    {
        // creating buffer queue
        Q q = new Q();
  
        // starting consumer thread
        new Consumer(q);
  
        // starting producer thread
        new Producer(q);
    }
}

Producción:

Producer produced item : 0
Consumer consumed item : 0
Producer produced item : 1
Consumer consumed item : 1
Producer produced item : 2
Consumer consumed item : 2
Producer produced item : 3
Consumer consumed item : 3
Producer produced item : 4
Consumer consumed item : 4

Explicación: como puede ver, las llamadas a put() y get() están sincronizadas, es decir, cada llamada a put() es seguida por una llamada a get() y no se pierde ningún elemento. Sin los semáforos, se habrían realizado varias llamadas a put() sin que coincidieran las llamadas a get(), lo que provocaría la pérdida de elementos. (Para probar esto, elimine el código de semáforo y observe los resultados).

La secuenciación de llamadas put() y get() es manejada por dos semáforos: semProd y semCon .

  • Antes de que put( ) pueda producir un artículo, debe adquirir un permiso de semProd. Después de producir el artículo, lanza semCon.
  • Antes de que get( ) pueda consumir un elemento, debe adquirir un permiso de semCon. Después de consumir el elemento, libera semProd.
  • Este mecanismo de «dar y recibir» asegura que cada llamada a put() debe ser seguida por una llamada a get().
  • Observe también que semCon se inicializa sin permisos disponibles. Esto asegura que put() se ejecute primero. La capacidad de establecer el estado de sincronización inicial es uno de los aspectos más poderosos de un semáforo.

Este artículo es una contribución de Gaurav Miglani . Si le gusta GeeksforGeeks y le gustaría contribuir, también puede escribir un artículo usando contribuya.geeksforgeeks.org o envíe su artículo por correo a contribuya@geeksforgeeks.org. Vea su artículo que aparece en la página principal de GeeksforGeeks y ayude a otros Geeks.

Escriba comentarios si encuentra algo incorrecto o si desea compartir más información sobre el tema tratado anteriormente.

Publicación traducida automáticamente

Artículo escrito por GeeksforGeeks-1 y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *