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

发布于 2024-11-04 06:09:10 字数 2277 浏览 1 评论 0原文

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

据我了解,消费者不会读取生产者生成的所有元素。 可能我没有正确理解 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 次迭代之后,消费者等待 NewItemEvent 被设置。

结果:生产者生产了 20 个元素。 消费者:出队只有 2 个元素。

我希望消费者将所有 20 个元素出列

根据一个例子,Consumer 是 Dequeue 20 个元素,问题是我对程序的理解是如何、为什么以及什么是错误的。

I don't understand how this example works http://msdn.microsoft.com/en-us/library/yy12yx1f(v=vs.80).aspx

As far as I understand Consumer doesn't read all elements produced by Producer.
Probably I don't understand correctly how AutoResetEvent works. Does it make sense to Set AutoreResetEvent several times?

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

This is how I understand example:

Producer:

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

Consumer:

    while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1)
    {
        lock (((ICollection)_queue).SyncRoot)
        {
            int item = _queue.Dequeue();
        }
        count++;
    } 
  1. Producer locks _queue:

           lock (((ICollection)_queue).SyncRoot)
    
  2. Producer adds 1 element into _queue and set NewItemEvent:

            _queue.Enqueue(r.Next(0,100));
            _syncEvents.NewItemEvent.Set();
    
  3. Consumer goes inside "while" loop because it received notification that NewItemEvent is set, NetItemEvent is now unset because it is AutoResetEvent:

           while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1)
    
  4. Consumer "froze" at next line waiting for _queue lock to be released:

           lock (((ICollection)_queue).SyncRoot)
    
  5. Producer continues add 19 more elements into _quere and release _queue object

  6. Consumer obtain a lock on _queue object and Dequeue one element:

        lock (((ICollection)_queue).SyncRoot)
        {
            int item = _queue.Dequeue();
        }
    
  7. Consumer executes second iteration of "while" loop because NewItemEvent is set, NetItemEvent is unset now because it is AutoResetEvent:

  8. After 2 iterations Consumer waits for NewItemEvent to be set.

Result: Producer produced 20 elements.
Consumer: Dequeue only 2 elements.

I expect Consumer to Dequeue all 20 elements.

According to an example Consumer is Dequeue 20 elements, the question is how, why and what' wrong in my understanding of the program.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

寄居人 2024-11-11 06:09:10

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

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

诚然,在我看来,这至少像是一个有点人为的例子,因为消费者不一定会消耗队列中的所有条目,但只要生产者继续生产它们,它就会继续消耗它们。

You've left out an important part of the example on the MSDN page, which is another loop around the main loop in the producer thread. The producer's job in the example is to try to keep at least 20 items in the queue.

Whenever it adds an item, the consumer is signaled, which causes it to remove an item, so there are fewer than 20 items in the queue. It doesn't matter whether this happens inside or outside the inner loop on the producer thread. The next time it reaches the while (_queue.Count < 20) it will be false, so the producer will add at least one more item to the queue, and resignal the consumer.

Admittedly, it seems to me at least like a somewhat contrived example, since the consumer can't ever necessarily consume all entries in the queue, but it does continue to consume items as long as the producer continues to produce them.

花伊自在美 2024-11-11 06:09:10

生产者将 20 个元素放入队列
消费者消费单个元素,将队列减少 1,现在队列计数为 19
生产者入队 ​​1 个元素队列现在为 20
消费者消耗单个元素,将队列减少 1,现在队列计数为 19

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

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

这个例子只是想向您展示如何处理将项目插入队列并通知消费者消费。想象一下,如果您有 20 个消费者都在消费,这将允许他们全部获取条目而不会破坏队列。

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

The producer enqueues 20 elements
The consumer consumes a single element, reduces the queue by one and now the queue count is 19
The producer enqueues 1 element queue is now at 20
The consumer consumes a single element, reduces the queue by one and now the queue count is 19

This continues until the exit event and leaves 19 items in the queue.

If you added a loop after the exit event fires and is handled by the consumer you could drain the rest of the queue.

This example is just trying to show you how you might handle inserting items into a queue and signal the consumer to consume. Imagine if you had 20 consumers all consuming this would allow them all to take an entry without trashing the queue.

Key take aways are: lock(_queue.SyncRoot) and Handling multiple events, one for the NewItem insert and one to exit out of the loop.

想挽留 2024-11-11 06:09:10

值得的是,MSDN 文章终于被删除了!只要只有一个消费者,代码就可以正常工作。但是,如果您扩展到两个或更多消费者,那么它很快就会崩溃,并可能使消费者活锁 在某些场景下。我和其他人已经对这篇文章喋喋不休了一段时间了,所以很高兴看到它最终消失了。

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

For what it is worth that MSDN article got removed...finally! The code worked alright as long as there was only a single consumer. However, if you scale up to two or more consumers then it quickly breaks down and can leave consumers live-locked in some scenarios. I, among others, have been harping about this article for quite some time now so it is nice to see that it finally went away.

Short answer...do not rely on that code for a real application.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文