生产者/消费者 msdn 示例如何工作?
我不明白这个示例是如何工作的 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++;
}
生产者锁
_queue
:lock (((ICollection)_queue).SyncRoot)
生产者向
_queue
添加1个元素并设置NewItemEvent
:_queue.Enqueue(r.Next(0,100)); _syncEvents.NewItemEvent.Set();
消费者进入“while”循环,因为它收到了
的通知NewItemEvent
已设置,NetItemEvent
现在未设置,因为它是 AutoResetEvent:while (WaitHandle.WaitAny(_syncEvents.EventArray) != 1)
消费者“冻结”在下一行,等待
_queue
锁被释放:lock (((ICollection)_queue).SyncRoot)
生产者继续向
_quere
添加 19 个元素并释放_queue
对象消费者获得锁定
_queue
对象和Dequeue
一个元素:lock (((ICollection)_queue).SyncRoot) { int item = _queue.Dequeue(); }
消费者执行“while”循环的第二次迭代,因为
NewItemEvent
已设置,NetItemEvent
现在未设置,因为它是 AutoResetEvent:在 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++;
}
Producer locks
_queue
:lock (((ICollection)_queue).SyncRoot)
Producer adds 1 element into
_queue
and setNewItemEvent
:_queue.Enqueue(r.Next(0,100)); _syncEvents.NewItemEvent.Set();
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)
Consumer "froze" at next line waiting for
_queue
lock to be released:lock (((ICollection)_queue).SyncRoot)
Producer continues add 19 more elements into
_quere
and release_queue
objectConsumer obtain a lock on
_queue
object andDequeue
one element:lock (((ICollection)_queue).SyncRoot) { int item = _queue.Dequeue(); }
Consumer executes second iteration of "while" loop because
NewItemEvent
is set,NetItemEvent
is unset now because it is AutoResetEvent: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 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您遗漏了 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.
生产者将 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.
值得的是,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.