开发者

How Producer/Consumer msdn example works?

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.


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.


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.


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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜