C#生产者/消费者模式
我有一个简单的单生产者/双消费者代码,如下所示,但输出显示只有C2
消耗。我的代码中是否有错误?C#生产者/消费者模式
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);
}
}
}
}
输出是:
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
出于测试目的,尝试加入消费者代码中的时间延迟。可能会出现这样的情况:“消费”速度如此之快,以至于一个消费者线程在其他消费者线程有机会之前清空队列。
(编辑)
正如我怀疑,增加一个
Thread.sleep代码(500);
在消费者线程内(模拟一些冗长的处理正在进行)导致两个线程都被使用。
当队列计数等于1时,你的生产者只调用Monitor.PulseAll,这并不是很常见,因为生产者没有做任何实质性的事情,这意味着通过门的第一个消耗线程会使队列中的队列第一个项目,第二个消耗线程将不会在队列中看到任何项目,因此点击Monitor.Wait,并且脉冲不会再发生(可能直到剩下最后一个项目为止),这样第二个线程就会处于等待状态无限地。
当第一个消耗线程通过门出现队列时,queue.Count变为0,并且下一次生产者入列一个项时,PulseAll将再次被命中。在这种情况下,我看不出为什么第二个线程会无限等待。 – Steve 2010-10-06 22:38:11
Added Thread.Sleep(500);在Consumer.comsume
然后我有以下的,
C2 Comsuming物品1 C1 Comsuming ITEM2 C2 Comsuming项目3 C1 Comsuming ITEM4 C2 Comsuming ITEM5 C1 Comsuming ITEM6 C2 Comsuming item7 C1 Comsuming item8 .....加入睡眠后,结果不确定。
哪个消费者消费哪个项目是不确定的,我认为它不会与作者的目的相冲突。 – Steve 2010-10-06 22:35:55
首先,我无法重现您的问题,这里两个线程都会消耗一些项目。我想你的机器更快,但像gw建议一样加入睡眠可以解决这个问题。 我还建议你不要尝试同步制作人,我的意思是让它尽可能快地排列项目并让消费者同步以查看谁处理每个项目。 我做了一个快速的修改和它似乎是做工精细:
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);
}
}
}
}
您也可以增加睡眠给消费者循环减慢。
不,我实际测试了原始代码,并从c1获得了一些输出,并从c2获得了一些输出。 – 2009-09-03 04:23:14
我跑过你的代码,并有c1的消耗和喷出c2的喷溅。你可能只想检查这个从msdn链接:How to: Synchronize a Producer and a Consumer Thread (C# Programming Guide)
该文章实际上在其建议的实现中存在缺陷。滚动到链接文章中的评论部分以查看它们。 – 2010-10-26 11:36:27
我认为你的目的是有多个消费线程“并行”工作。但是你的代码效率很低。这两个消耗线程本质上是连续工作的。实际的工作代码应该放在锁之外,这样两个使用者线程才能真正并行运行。如果您拥有多个内核或者甚至在单个核心计算机上,这取决于工作的属性,这会改善运行时间。否则,实际上没有必要拥有多个消耗线程,因为无论如何,它们都会消耗顺序运行的线程。
谢谢史蒂夫,你有一个例子吗? – Robs 2011-05-31 18:46:19
你能描述一下你究竟想达到什么吗?你的例子看起来有点人为,所以我不能从上下文中确定你需要做什么。 – jrista 2009-09-03 03:10:55
嗨南南,请看看[这个生产者消费者的例子](https://stackoverflow.com/questions/733793/implementing-the-producer-consumer-pattern-in-c-sharp/47179576#47179576),它可能会帮助你。 – 2017-11-08 12:58:50