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

本文关键字:何工作 工作 消费者 msdn 生产者 | 更新日期: 2023-09-27 17:53:48

我不明白这个例子是如何工作的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. 生产者在_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个元素。消费者:Dequeue只有2个元素。

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

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

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

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

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

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

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

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

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

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

Key take away是:lock(_queue.SyncRoot)和Handling多个事件,一个用于NewItem插入,一个用于退出循环。

这篇MSDN文章终于被删除了!只要只有一个消费者,代码就可以正常工作。但是,如果您扩展到两个或更多的消费者,那么它很快就会崩溃,并且在某些情况下可能会使消费者处于动态锁定状态。我和其他一些人一直在喋喋不休地谈论这篇文章,所以很高兴看到它终于消失了。

简短的回答…对于实际的应用程序,不要依赖于这些代码。