AutoResetEvent过程?
private ConcurrentQueue<Data> _queue = new ConcurrentQueue<Data>();
private AutoResetEvent _queueNotifier = new AutoResetEvent(false);
public void MoreData(Data example)
{
_queue.Enqueue(example);
_queueNotifier.Set();
}
private void _SimpleThreadWorker()
{
while (_socket.Connected)
{
_queueNotifier.WaitOne();
Data data;
if (_queue.TryDequeue(out data))
{
//handle the data
}
}
}
一旦事件出队,我是否必须将其设置为 false,或者当事件返回 _queueNotifier.WaitOne()
时,它会自行返回 false 或者它是如何工作的?
我应该像下面的示例一样使用内部 while 还是两种方式都很好/相等?
while (_socket.Connected)
{
_queueNotifier.WaitOne();
while (!_queue.IsEmpty)
{
Data data;
if (_queue.TryDequeue(out data))
{
//handle the data
}
}
}
private ConcurrentQueue<Data> _queue = new ConcurrentQueue<Data>();
private AutoResetEvent _queueNotifier = new AutoResetEvent(false);
public void MoreData(Data example)
{
_queue.Enqueue(example);
_queueNotifier.Set();
}
private void _SimpleThreadWorker()
{
while (_socket.Connected)
{
_queueNotifier.WaitOne();
Data data;
if (_queue.TryDequeue(out data))
{
//handle the data
}
}
}
Do I have to set the event to false once I have it Dequeue or the event goes back to false on it's own when it hits back _queueNotifier.WaitOne()
or how it works exactly ?
Should I use a inner while like the below example instead or both ways are just fine/equal ?
while (_socket.Connected)
{
_queueNotifier.WaitOne();
while (!_queue.IsEmpty)
{
Data data;
if (_queue.TryDequeue(out data))
{
//handle the data
}
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
如果您使用 .NET 4 中的
ConcurrentQueue
,最好避免完全由AutoResetEvent
自行处理。相反,创建一个BlockingCollection
来包装ConcurrentQueue
并使用它 - 它可以完成您需要的一切。 (如果您只是使用无参数构造函数创建一个BlockingCollection
,它无论如何都会为您创建一个ConcurrentQueue
。)编辑:如果您确实想仍然使用
AutoResetEvent
,然后WaitOne
将自动(并且原子地)重置事件 - 这是AutoResetEvent
的“自动”部分。将此与ManualResetEvent
进行比较,后者不会重置事件。If you're using
ConcurrentQueue
from .NET 4, it's best to avoid doing theAutoResetEvent
handling yourself entirely. Instead, create aBlockingCollection
to wrap theConcurrentQueue
and just use that - it does everything you need. (If you just create aBlockingCollection
using the parameterless constructor, it'll create aConcurrentQueue
for you anyway.)EDIT: If you really want to still use
AutoResetEvent
, thenWaitOne
will automatically (and atomically) reset the event - that's the "Auto" part ofAutoResetEvent
. Compare this withManualResetEvent
which doesn't reset the event.当您执行
_queueNotifier.Set()
时,事件将发出信号。当事件发出信号并且从另一个线程调用 _queueNotifier.WaitOne() 时,会同时发生两件事(即在内核模式下):WaitOne
已解锁,因此您不必自己显式设置事件状态。
然而,正如 Jon 所说,如果您对共享变量所做的唯一事情就是从队列中推送和拉出项目,那么简单地使用
BlockingCollection
会更方便。如果您正在访问多个共享变量,那么围绕它使用单线程同步机制(您自己的)可能是有意义的。
另外,在我看来,如果您打算使用自己的代码,最好这样做:
这样,每当项目添加到当消费者功能繁忙时排队。您还可以避免在消费者函数的每次迭代中进入内核模式。
确实,对于后者,避免上下文切换是以添加
_queue.IsEmpty
测试为代价的(其中糟糕的实现无论如何都可能会进行上下文切换);但是,该操作可能是作为互锁比较交换操作实现的,不需要进入内核模式。免责声明:我没有检查源代码或IL来验证上述信息。
When you do
_queueNotifier.Set()
the event becomes signaled. When the event is signaled and_queueNotifier.WaitOne()
is called from the other thread, two things happen simultaneously (i.e. in kernel mode):WaitOne
is unblockedSo you don't have to explicitly set the event status yourself.
However, as Jon says, if the only thing you are doing with your shared variables is to push and pull items from the queue, simply using a
BlockingCollection
is more convenient.If you are accessing multiple shared variables then it might make sense to have a single thread sync mechanism (your own) around that.
Also, it seems to me that if you are going to use your own code it would be better to do something like this:
This way you won't have to go into kernel mode (to set the event) whenever items get added to the queue while the consumer function is busy. You also avoid going into kernel mode in each iteration of the consumer function.
It's true that regarding the latter, avoiding the context switch comes at the cost of adding the
_queue.IsEmpty
test (wherein a bad implementation might do a context switch anyway); however, that one is probably implemented as an interlocked compare exchange operation which doesn't require going into kernel mode.Disclaimer: I have not checked source code or IL to verify the above information.