【问题标题】:How Producer/Consumer msdn example works?生产者/消费者 msdn 示例如何工作?
【发布时间】:2011-04-30 12:21:16
【问题描述】:

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

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

    _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. Producer 将 1 个元素添加到 _queue 并设置 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. Producer 继续向 _quere 添加 19 个元素并释放 _queue 对象

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

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

  8. 2 次迭代后,消费者等待设置 NewItemEvent。

结果:Producer 制作了 20 个元素。 消费者:Dequeue 只有 2 个元素。

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

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

【问题讨论】:

    标签: c# multithreading


    【解决方案1】:

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

    每当它添加一个项目时,都会向消费者发出信号,这会导致它删除一个项目,因此队列中的项目少于 20 个。这是否发生在生产者线程的内部循环内部或外部都没有关系。下次它到达while (_queue.Count &lt; 20) 时,它将为假,因此生产者将至少再向队列添加一项,并重新通知消费者。

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

    【讨论】:

      【解决方案2】:

      生产者将 20 个元素加入队列 消费者消费单个元素,将队列减一,现在队列数为 19 生产者入队 ​​1 个元素队列现在为 20 消费者消费单个元素,将队列减一,现在队列数为 19

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

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

      此示例只是试图向您展示如何处理将项目插入队列并向消费者发出消费信号。想象一下,如果您有 20 个消费者都在消费,这将允许他们都接受一个条目而不会破坏队列。

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

      【讨论】:

      • 谢谢,如何修改示例,如果我想要 1) 队列是无限的; 2) 消费者应该尽快出列元素吗?
      【解决方案3】:

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-10-19
        • 1970-01-01
        • 1970-01-01
        • 2016-07-19
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多