2009-09-03 23 views
7

Tengo el código simple de un productor/dos consumidores de la siguiente manera, pero el resultado muestra que solo C2 consume. ¿Hay algún error en mi código?C# Producer/Consumer pattern

class Program 
{ 
    static void Main(string[] args) 
    { 
     Object lockObj = new object(); 
     Queue<string> queue = new Queue<string>(); 
     Producer p = new Producer(queue, lockObj); 
     Consumer c1 = new Consumer(queue, lockObj, "c1"); 
     Consumer c2 = new Consumer(queue, lockObj, "c2"); 

     Thread t1 = new Thread(c1.consume); 
     Thread t2 = new Thread(c2.consume); 
     t1.Start(); 
     t2.Start(); 

     Thread t = new Thread(p.produce); 
     t.Start(); 

     Console.ReadLine(); 
    } 
} 
public class Producer 
{ 
    Queue<string> queue; 
    Object lockObject; 
    static int seq = 0; 
    public Producer(Queue<string> queue, Object lockObject) 
    { 
     this.queue = queue; 
     this.lockObject = lockObject; 
    } 

    public void produce() 
    { 
     while(seq++ <15) //just testinng 15 items 
     { 
      lock (lockObject) 
      { 
       string item = "item" + seq; 
       queue.Enqueue(item); 
       Console.WriteLine("Producing {0}", item); 
       if (queue.Count == 1) 
       { // first 
        Monitor.PulseAll(lockObject); 
       } 
      } 
     } 
    } 

} 

public class Consumer 
{ 
    Queue<string> queue; 
    Object lockObject; 
    string name; 
    public Consumer(Queue<string> queue, Object lockObject, string name) 
    { 
     this.queue = queue; 
     this.lockObject = lockObject; 
     this.name = name; 
    } 

    public void consume() 
    { 
     string item; 
     while (true) 
     { 
      lock (lockObject) 
      { 
       if (queue.Count == 0) 
       { 
        Monitor.Wait(lockObject); 
        continue; 
       } 
       item = queue.Dequeue(); 
       Console.WriteLine(" {0} Consuming {1}", name, item); 
      } 
     } 
    } 
} 

La salida es:

Producing item1 
c2 Consuming item1 

Producing item2 
c2 Consuming item2 

Producing item3 
c2 Consuming item3 

Producing item4 
c2 Consuming item4 

Producing item5 
c2 Consuming item5 

Producing item6 
c2 Consuming item6 

Producing item7 
c2 Consuming item7 

Producing item8 
c2 Consuming item8 

Producing item9 
c2 Consuming item9 

Producing item10 
c2 Consuming item10 

Producing item11 
c2 Consuming item11 

Producing item12 
c2 Consuming item12 

Producing item13 
c2 Consuming item13 

Producing item14 
c2 Consuming item14 

Producing item15 
c2 Consuming item15 
+0

¿Podría describir qué es exactamente lo que está tratando de lograr? Tu ejemplo se ve un poco artificial, por lo que no puedo determinar desde el contexto lo que debes hacer. – jrista

+0

Hola, Southsouth, mira este [ejemplo Productor-Consumidor] (https://stackoverflow.com/questions/733793/implementing-the-producer-consumer-pattern-in-c-sharp/47179576#47179576), te puede ayudar –

Respuesta

4

Para propósitos de prueba, trate de añadir un retardo de tiempo dentro del código de consumo. Puede ser que el "consumo" sea tan rápido que un hilo de consumidor vacíe la cola antes de que el otro hilo de consumidor tenga una posibilidad.

(edit)

como sospechaba, añadiendo un

Thread.Sleep (500);

dentro del hilo del consumidor (para simular que se está procesando algo), ambos hilos se utilizan.

2

Su productor solo llama a Monitor.PulseAll cuando el recuento de cola es igual a 1, lo que no será muy frecuente ya que el productor no hace nada de sustancia, esto significa que el primer hilo de consumo a través de la puerta primer elemento, el segundo hilo de consumo no verá ningún elemento en la cola y, por lo tanto, presiona el Monitor. Espera, y el Pulso no volverá a suceder (probablemente hasta que quede el último elemento) para que el segundo hilo quede en esa espera infinitamente

+1

Cuando el primer hilo de consumo a través de la puerta llega a dequearse, la cola.Cuenta se convierte en 0 y la próxima vez que el productor pone en cola un elemento, PulseAll se volverá a golpear. No puedo ver por qué el segundo hilo se sentará y esperará infinitamente en este caso. – Steve

0

Thread.Sleep añadido (500); en Consumer.comsume

entonces he la siguiente,

c2 comsuming item1 c1 comsuming item2 c2 comsuming elemento3 c1 comsuming item4 c2 comsuming item5 c1 comsuming Item6 c2 comsuming item7 c1 comsuming item8 ..... el resule no es incierto después de agregar Sleep.

+0

Qué consumidor consume qué artículo es incierto y creo que no entraría en conflicto con el propósito del autor. – Steve

5

Primero, no puedo reproducir su problema, aquí ambos hilos consumen algunos de los elementos. Supongo que su máquina es más rápida, pero agregar Sleep like gw lo solucionará. Lo que también sugeriría es que no intente sincronizar el productor, es decir, deje que coloque en cola los elementos lo más rápido posible y permita que los consumidores se sincronicen para ver quién maneja cada artículo. me hizo una modificación rápida y parece estar funcionando bien:

static void Main() 
    { 
     Object lockObj = new object(); 
     Queue<string> queue = new Queue<string>(); 
     Producer p = new Producer(queue); 
     Comsumer c1 = new Comsumer(queue, lockObj, "c1"); 
     Comsumer c2 = new Comsumer(queue, lockObj, "c2"); 

     Thread t1 = new Thread(c1.consume); 
     Thread t2 = new Thread(c2.consume); 
     t1.Start(); 
     t2.Start(); 

     Thread t = new Thread(p.produce); 
     t.Start(); 

     Console.ReadLine(); 
    } 
} 
public class Producer 
{ 
    Queue<string> queue; 
    static int seq; 
    public Producer(Queue<string> queue) 
    { 
     this.queue = queue; 
    } 

    public void produce() 
    { 
     while (seq++ < 1000) //just testinng 15 items 
     { 
      string item = "item" + seq; 
      queue.Enqueue(item); 
      Console.WriteLine("Producing {0}", item);     
     } 
    } 
} 

public class Comsumer 
{ 
    Queue<string> queue; 
    Object lockObject; 
    string name; 
    public Comsumer(Queue<string> queue, Object lockObject, string name) 
    { 
     this.queue = queue; 
     this.lockObject = lockObject; 
     this.name = name; 
    } 

    public void consume() 
    { 
     string item; 
     while (true) 
     { 
      lock (lockObject) 
      { 
       if (queue.Count == 0) 
       { 
        continue; 
       } 
       item = queue.Dequeue(); 
       Console.WriteLine(" {0} Comsuming {1}", name, item); 
      }     
     } 
    } 
} 

También puede añadir el sueño para frenar los bucles de consumo.

+0

No, de hecho probé el código original y obtuve algunos resultados de c1 y algunos de c2. –

0

Creo que su propósito es que más de uno consuma hilos trabajando "en paralelo". Pero tu código es poco eficiente. Los dos hilos de consumo funcionan esencialmente de forma secuencial. El código de trabajo real debe colocarse fuera del bloqueo para que los dos hilos de consumidor puedan ejecutarse en paralelo real. Esto mejora el tiempo de ejecución si tiene múltiples núcleos o incluso en una sola máquina central según la propiedad del trabajo. De lo contrario, no tiene sentido tener más de un hilo de consumo porque, de todos modos, todos los hilos de consumo se ejecutan en secuencia.

+0

Gracias Steve, ¿tienes un ejemplo? – Robs