Uso correcto de los semaforos (Productor - Consumidor)

1,289 views
Skip to first unread message

Cesar Perez Ramirez

unread,
May 29, 2011, 9:33:52 AM5/29/11
to altnet-...@googlegroups.com
Que tal buen día ,

Tengo una duda con respecto al threading y a los semáforos  , les explico un poco de mi código..

Mi semáforo lo he declarado así :

Semaphore sem = new Semaphore(0,1);// para que solo un hilo pueda ocuparlo


Tengo dos clases que cada una tiene un metodo  principal y estan basadas en el modelo Productor - Consumidor 

Producer.Run()
Consumer.Run()


los cuales ejecuto desde el ThreadPool para que se encuentren en diferente hilo:
            ThreadPool.QueueUserWorkItem(new WaitCallback(producer.RunProductorAsync), autoEvent);            
            ThreadPool.QueueUserWorkItem(new WaitCallback(consumer.Run), autoEvent);


Cabe destacar que ambas clases Reciben el MISMO semaforo por referencia.

de manera que en el codigo del metodo Run del productor tengo lo siguiente

        public void RunProductorAsync(Object StateInfo)
          {
              
            CGauss NumGauss = new CGauss(); //Esta clase contiene metodos que  genera un numero de Distribucion Gaussiana aleatorio

            for (int i = 0; i < _M; i++)   //se genera ese numero M veces
            {
                
                Semaforo.WaitOne();//AQUI UN PROBLEMA ----Se supone que si nadie lo esta ocupando como es el caso ... deberia continuar con su trabajo sin problema 

                                               // pero SE DETIENE y no llega a ningun lado
                
                DQueue.Enqueue(NumGauss.GetNormal(_Mu, _Sigma));//Generando el Dato Gaussiano

                
                Semaforo.Release();//Se libera el semaforo para que el consumidor pueda hacer su trabajo
                
                ((AutoResetEvent)StateInfo).Set();
            }
            DQueue.Enqueue(true);//Se notifica que ya ha terminado el proceso
            
   
        }
-  - - -  - -  - - - - -  - - - - - -  - -  - -  - -  - - - - -  - 


Y de hecho ya no se ejecuta el Consumidor ...

según lo que he consultado en las paginas de MSDN de MicroSoft y de diversos programadores ,  debería de estar trabajando correctamente , pero no es asi , inclusive ya conseguí el libro Fco.Javier Ceballos 
y tampoco encuentro donde puedo estar equivocado .



De ante mano les agradezco mucho la ayuda , me trae vuelto loco este problema

Angel Java Lopez

unread,
May 29, 2011, 10:27:00 AM5/29/11
to altnet-...@googlegroups.com
Hola gente!

Hmmm... Cesar, nunca use el Semaphore de .NET. Pero recien lei:
http://msdn.microsoft.com/en-us/library/system.threading.semaphore.aspx

Por lo que parece, tu semaforo inicia con cuenta en 0. Y entonces, cualquier .WaitOne() quedara bloqueado. Se necesita un Release.

Probaria entonces dos opciones:

new Semaphore(1,1) // para que la cuenta sea 1 al comienzo

o

sem.Release() // en el programa principal, para dejar pasar a alguno de los que esperan .WaitOne()

Funciono?

Nos leemos!

Angel "Java" Lopez
http://www.ajlopez.com
http://twitter.com/ajlopez


--
Has recibido este mensaje porque estás suscrito al grupo "AltNet-Hispano" de Grupos de Google.
Para publicar una entrada en este grupo, envía un correo electrónico a altnet-...@googlegroups.com.
Para anular tu suscripción a este grupo, envía un correo electrónico a altnet-hispan...@googlegroups.com
Para tener acceso a más opciones, visita el grupo en http://groups.google.com/group/altnet-hispano?hl=es.

Cesar Perez Ramirez

unread,
May 29, 2011, 10:45:33 AM5/29/11
to altnet-...@googlegroups.com
Muchas Gracias por la respuesta , ya lo habia intentado , pero de alguna manera "Macabra (misteriosamente terrorifica)", en determinado momento deja pasar a los 2 subprocesos.

2011/5/29 Angel Java Lopez <ajlop...@gmail.com>

Angel Java Lopez

unread,
May 29, 2011, 12:00:19 PM5/29/11
to altnet-...@googlegroups.com
Ah! A ver si entendi...

Como determinas que "deja pasar a los 2 subprocesos"?

Tienes el codigo de Consumidor? Me imagino que te pasa que el consumidor "entra" cuando todavia el productor no "produjo" el correspondiente item.

Yo, en general, cuando planteo Consumidor/Productor, los hago depender de alguna Cola, y es la cola la que tiene todo el codigo de sincronizacion. Eso permite tambien que haya n consumidores y m productores, en cualquier momento, todos compitiendo/compartiendo la misma Cola.

Habra solucion usando UN SOLO SEMAFORO?

En
http://en.wikipedia.org/wiki/Producer-consumer_problem
la solucion usa dos semaforos, lo que parece razonable.

Aca hay una solucion esquematica con un solo semaforo:
http://www.cs.mtu.edu/~shene/NSF-3/e-Book/SEMA/TM-example-buffer.html
PERO HACEN ALGO MAS: Chequea cuando esta un buffer intermedio lleno o vacio.

Como lo resuelven los autores que nombraste? Enlace a codigo/articulo? Usan un solo semaforo? seudocodigo de su solucion?

Volviendo a tu problema. Se ocurre, para consumidor, productor, y dos semaforos, cosas como (seudocodigo, consumidor y productor tienen acceso a los dos semaforos):

sem1 = new Sem(0,1);
sem2 = new Sem(1,1);

productor.Run

while true
      sem2.WaitOne()
      enqueue(newitem)
      sem1.Release()


consumidor.Run
while true
     sem1.WaitOne()
     newitem = dequeue()
     sem2.Release()

Hmmm.. hasta deberia funcionar para varios consumidores productores. Como veo que solo quieres manejar de a un item por vez, tal vez el uso de una cola es excesivo: no habria mas de un elemento en la cola al mismo tiempo. Supongo que no quieres usar una Cola multithread-safe, y que quieres aprender sobre semaforos. Pero en .NET 4, podria aprovechar directamente colas bloqueantes, sin necesidad de semaforos y otros adminiculos.

Ver por ejemplo
http://stackoverflow.com/questions/801528/thread-safe-blocking-queue-implementation-on-net

En .NET 3.x yo use
http://ajlopez.wordpress.com/2010/01/02/goroutines-and-channels-in-c/
Ejemplo
http://ajlopez.wordpress.com/2010/02/07/genetic-algorithms-using-goroutines-and-channels-in-c/
El Channel class funcionaria como una cola intermedia de un solo elemento a la vez, que entiendo es lo que hace tu ejemplo.

Pero me gusta mas directamente en AjSharp ;-)
http://ajlopez.wordpress.com/2009/12/28/channels-and-goroutines-in-ajsharp-part-1/
http://ajlopez.wordpress.com/2009/12/30/channels-and-goroutines-in-ajsharp-part-2/

Un Channel con Queue (que admite mas de un elemento a la vez):
http://ajlopez.wordpress.com/2010/01/27/queue-channels-in-ajsharp/

Bueno, tiempo de almuerzo, aqui!

Cesar Perez Ramirez

unread,
May 29, 2011, 12:17:58 PM5/29/11
to altnet-...@googlegroups.com
pues tengo una Cola tambien pero solo me sirve para dos cosas , para guardar los datos del productor y para saber cuando ya ternino el productor de emitir datos, y si supongo eso, que tambien entra por que la cola esta vacia y me genera errores

Cesar Perez Ramirez

unread,
May 29, 2011, 12:33:58 PM5/29/11
to altnet-...@googlegroups.com
Y ese era el problema , muchas gracias por tu ayuda , el punto es que aveces entra antes el Consumidor.
Thanks A lot!!

Saludos y Buen Dia.

Angel Java Lopez

unread,
Jun 1, 2011, 9:00:51 AM6/1/11
to altnet-...@googlegroups.com
Ah! Y como fue la solucion?

Cesar Perez Ramirez

unread,
Jun 1, 2011, 9:13:21 AM6/1/11
to altnet-...@googlegroups.com
Metí una variable para que el productor supiera que ya había sido consumido el producto anterior antes de hacer el bloqueo y del lado del consumidor , condicione el bloqueo a que la cola no estuviera vacia....
Gracias y Saludos

2011/6/1 Angel Java Lopez <ajlop...@gmail.com>
Reply all
Reply to author
Forward
0 new messages