C#生产者/消费者模式

时间:2009-09-03 03:06:04

标签: c# producer-consumer

我有简单的one-producer / two-consumer代码,如下所示,但输出显示只有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

6 个答案:

答案 0 :(得分:6)

首先,我无法重现您的问题,这里两个线程都消耗了一些项目。我想你的机器速度更快,但像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);
            }                
        }
    }
}

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

答案 1 :(得分:4)

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

(编辑)

我怀疑,添加一个

Thread.sleep代码(500);

消费者线程中的

(模拟正在进行的一些冗长的处理)导致两个线程被利用。

答案 2 :(得分:2)

当队列计数等于1时,你的生产者只调用Monitor.PulseAll,这不会经常发生,因为生产者没有做任何实质内容,这意味着通过门的第一个消耗线程会使第一个队列出列item,第二个消费线程将看不到队列中的任何项目,因此点击Monitor.Wait,并且Pulse不会再次发生(可能直到除最后一个项目之外的所有项目),以便第二个线程将无限期地等待

答案 3 :(得分:0)

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

然后我有以下内容,

c2清楚item1 c1清楚项目2 c2清楚项目3 c1清楚项目4 c2消耗item5 c1清楚项目6 c2清楚项目7 c1清楚项目8 ..... 添加睡眠后,resule不确定。

答案 4 :(得分:0)

我运行了你的代码并且c1的喷射进行消耗和喷射c2。您可能只想查看来自msdn:How to: Synchronize a Producer and a Consumer Thread (C# Programming Guide)

的链接

答案 5 :(得分:0)

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