C# Producer/Consumer-Muster
Habe ich einfache ein-Produzent - /zwei-Verbraucher-code wie folgt, aber die Ausgabe zeigt, dass nur C2
verbraucht. Gibt es irgendwelche Fehler in meinem code?
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);
}
}
}
}
Ausgabe:
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
- Kannst du beschreiben, was genau du zu erreichen versuchst? Dein Beispiel sieht ein bisschen künstlich, so dass ich nicht bestimmen kann, aus dem Kontext, was Sie tun müssen.
- Hi Süd-Süd, nehmen Sie bitte einen Blick auf diese Erzeuger-Verbraucher-Beispiel, vielleicht hilft es Euch.
Du musst angemeldet sein, um einen Kommentar abzugeben.
Erstens kann ich nicht nachvollziehen dein problem, hier die beiden threads verbrauchen einige der Elemente. Ich denke mal, deine Maschine ist schneller, aber das hinzufügen Schlafen wie gw vorschlagen, wird das lösen.
Was würde ich auch vorschlagen, ist, dass Sie nicht versuchen, zu synchronisieren, der Produzent, ich meine, lassen Sie es queue-Objekte so schnell wie Sie können und lassen die Verbraucher zu synchronisieren, um zu sehen, wer kümmert sich um jedes Element.
Ich machte eine schnelle änderung, und es scheint einwandfrei zu funktionieren:
Sie können auch hinzufügen, die den Schlaf zu einer Verlangsamung der Verbraucher Schleifen.
Für Testzwecke, versuchen Sie, eine Zeitverzögerung innerhalb der consumer-code. Es kann der Fall sein, dass "Verbrauch" ist so schnell, dass ein Verbraucher-thread die Warteschlange geleert, bevor die anderen consumer thread eine chance hat.
(edit)
Wie ich vermutete, das hinzufügen einer
Thread.Sleep(500);
innerhalb der consumer-thread (simulieren einige längere Verarbeitung geht) Ergebnisse in beiden threads genutzt.
Ihre Produzenten nur Anrufe Überwachen.PulseAll, wenn die queue count gleich 1 ist, die wird nicht sehr oft nichts von Substanz getan wird, von den Produzenten bedeutet dies, dass die zuerst verbrauchen Faden durch das Tor bekommt zum entfernen das erste Element, das zweite verbrauchen thread sehen keine Elemente in der queue und so traf der Monitor.Warten, und der Puls wird nicht wieder vorkommen (wahrscheinlich, bis alle, aber das Letzte Element ist Links), so dass der zweite thread sitzen, die warten unendlich.
Hinzugefügt Thread.Sleep(500); in der Verbraucher.comsume
dann habe ich die folgenden,
c2 Comsuming item1
c1 Comsuming item2
c2-Comsuming item3
c1 Comsuming item4
c2-Comsuming item5
c1 Comsuming item6
c2-Comsuming item7
c1 Comsuming item8
.....
die resule ist nicht unsicher nach dem hinzufügen Schlafen.
Ich lief Sie den code und hatte Schüben von c1 tun, das verarbeiten und spritzt der c2. Können Sie nur wollen, prüfen Sie diesen link aus dem msdn: Gewusst wie: Synchronisieren von einem Producer und einem Consumer-Thread (C# - Programmierhandbuch)
Denke ich, Ihr Zweck ist es, mehr als man konsumieren threads arbeiten "parallel". Aber dein code ist gering effizient. Die beiden verbrauchen threads arbeiten sequenziell im wesentlichen. Die tatsächliche Arbeitszeit-code sein sollte, setzen Sie außerhalb der Sperre, so dass die beiden consumer-threads ausgeführt werden können in Echtzeit parallel. Dies verbessert die Laufzeit, wenn Sie mehrere Kerne oder sogar auf einem single-core-Maschine je nach Eigenschaft der Arbeit. Ansonsten, gibt es eigentlich keinen Punkt mehr zu haben als man verbrauchen thread, da sowieso alle verbrauchen threads laufen sequentiell.