7

我有如下简单的一个生产者/两个消费者的代码,但输出显示只有C2消耗。我的代码中是否有任何错误?

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
4

6 回答 6

6

首先,我无法重现您的问题,这里两个线程都消耗了一些项目。我猜你的机器速度更快,但是像 gw 建议那样添加 Sleep 可以解决这个问题。我还建议您不要尝试同步生产者,我的意思是让它尽可能快地排队项目并让消费者同步以查看谁处理每个项目。我做了一个快速修改,它似乎工作正常:

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);
            }                
        }
    }
}

您还可以添加睡眠以减慢消费者循环。

于 2009-09-03T03:57:41.780 回答
4

出于测试目的,请尝试在消费者代码中添加时间延迟。可能是“消费”如此之快,以至于一个消费者线程在另一个消费者线程有机会之前清空队列。

(编辑)

正如我所怀疑的,添加一个

线程.睡眠(500);

在消费者线程内部(模拟一些冗长的处理过程)导致两个线程都被使用。

于 2009-09-03T03:12:57.377 回答
2

您的生产者仅在队列计数等于 1 时调用 Monitor.PulseAll,这不会经常发生,因为生产者没有做任何实质性的事情,这意味着通过门的第一个消费线程将第一个项目出列,第二个消费线程将在队列中看不到任何项目,因此点击 Monitor.Wait,并且脉冲不会再次发生(可能直到剩下最后一个项目之外的所有项目),因此第二个线程将无限等待。

于 2009-09-03T03:13:42.243 回答
0

添加了 Thread.Sleep(500);在 Consumer.comsume

然后我有以下内容,

c2 Comsuming item1 c1 Comsuming item2 c2 Comsuming item3 c1 Comsuming item4 c2 Comsuming item5 c1 Comsuming item6 c2 Comsuming item7 c1 Comsuming item8 .....加上Sleep后resule不确定。

于 2009-09-03T03:39:23.767 回答
0

我运行了你的代码,并且有 c1 的冲刺做 c2 的消耗和冲刺。您可能只想查看 msdn 中的此链接:如何:同步生产者和消费者线程(C# 编程指南)

于 2009-09-03T04:09:51.617 回答
0

我认为您的目的是让多个消耗线程“并行”工作。但是您的代码效率低下。两个消费线程本质上是按顺序工作的。实际的工作代码应该放在锁之外,这样两个消费者线程就可以真正并行运行。如果您有多个内核,甚至在单核机器上,这将提高运行时间,具体取决于工作的属性。否则,实际上没有必要拥有多个消费线程,因为无论如何,所有消费线程都是按顺序运行的。

于 2010-10-06T22:41:19.377 回答