生产者/消费者msdn示例如何工作?

时间:2011-04-30 12:21:16

标签: c# multithreading

我不明白这个例子是如何运作的http://msdn.microsoft.com/en-us/library/yy12yx1f(v=vs.80).aspx

据我所知,Consumer不会读取Producer生成的所有元素。 可能我不能正确理解AutoResetEvent的工作原理。 Set AutoreResetEvent几次有意义吗?

    _newItemEvent = new AutoResetEvent(false);
    _newItemEvent.Set();
    _newItemEvent.Set();
    _newItemEvent.Set();
    _newItemEvent.Set();

这就是我理解的例子:

制片:

        lock (((ICollection)_queue).SyncRoot)
        {
            while (_queue.Count < 20)
            {
                _queue.Enqueue(r.Next(0,100));
                _syncEvents.NewItemEvent.Set();
                count++;
            }
        }

消费者:

    while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1)
    {
        lock (((ICollection)_queue).SyncRoot)
        {
            int item = _queue.Dequeue();
        }
        count++;
    } 
  1. 制作人锁定_queue

           lock (((ICollection)_queue).SyncRoot)
    
  2. 制作人在_queue中添加1个元素并设置NewItemEvent

            _queue.Enqueue(r.Next(0,100));
            _syncEvents.NewItemEvent.Set();
    
  3. 消费者进入“while”循环,因为它收到NewItemEvent已设置的通知,NetItemEvent现在未设置,因为它是AutoResetEvent:

           while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1)
    
  4. 消费者在下一行“冻结”,等待释放_queue锁定:

           lock (((ICollection)_queue).SyncRoot)
    
  5. 制作人继续在_quere中添加19个元素并释放_queue对象

  6. 消费者获取_queue个对象和Dequeue一个元素的锁定:

        lock (((ICollection)_queue).SyncRoot)
        {
            int item = _queue.Dequeue();
        }
    
  7. 消费者执行“while”循环的第二次迭代,因为NewItemEvent已设置,NetItemEvent现在未设置,因为它是AutoResetEvent:

  8. 经过2次迭代后,Consumer等待设置NewItemEvent。

  9. 结果:制片人制作了20个元素。 消费者:Dequeue只有2个元素。

    我希望消费者能够Dequeue所有20个元素。

    根据一个例子,消费者是Dequeue 20个元素,问题是我对该计划的理解方式,原因和错误。

3 个答案:

答案 0 :(得分:2)

您在MSDN页面上省略了该示例的一个重要部分,这是生产者线程中主循环的另一个循环。生产者在该示例中的工作是尝试在队列中保留至少20个项目。

每当它添加一个项目时,就会通知消费者,这会导致它删除一个项目,因此队列中的项目少于20个。这是发生在生产者线程内部循环内部还是外部并不重要。下次到达while (_queue.Count < 20)时,它将为false,因此生产者将至少再向队列中添加一个项目,并重新使用该消费者。

不可否认,在我看来,至少就像一个有点人为的例子,因为消费者不一定能消耗队列中的所有条目,但只要生产者继续生产它们,它就会继续消耗物品。 / p>

答案 1 :(得分:0)

制片人排队20个元素 消费者使用单个元素,将队列减少一个,现在队列数为19 生产者排队1个元素队列现在是20 消费者使用单个元素,将队列减少一个,现在队列数量为19

这一直持续到退出事件并在队列中留下19个项目。

如果您在退出事件触发后添加了一个循环并由消费者处理,则可能会耗尽队列的其余部分。

这个例子只是试图向您展示如何处理将项目插入队列并指示消费者使用的信号。想象一下,如果你有20个消费者全部消费,这将允许他们所有人都进入一个条目而不会破坏队列。

关键要点是:lock(_queue.SyncRoot)和处理多个事件,一个用于NewItem插入,另一个用于退出循环。

答案 2 :(得分:0)

MSDN文章被删除了......最后!只要只有一个消费者,代码就可以正常工作。但是,如果您扩展到两个或更多消费者,那么它会很快崩溃,并且可能会在某些情况下让消费者live-locked离开。我和其他人一直在讨论这篇文章很长一段时间,所以很高兴看到它终于消失了。

简短回答......不要依赖该代码来实现真正的应用程序。