C# 自动还原过程?

C# 自动还原过程?,c#,autoresetevent,concurrent-collections,C#,Autoresetevent,Concurrent Collections,如果您使用的是.NET4中的ConcurrentQueue,最好避免完全由您自己处理AutoResetEvent。相反,创建一个包来包装ConcurrentQueue并使用它——它可以完成您所需要的一切。如果您只是使用无参数构造函数创建一个BlockingCollection,它无论如何都会为您创建一个ConcurrentQueue 编辑:如果你真的想继续使用AutoResetEvent,那么WaitOne会自动自动重置事件-这是AutoResetEvent的自动部分。将此与ManualRese

如果您使用的是.NET4中的ConcurrentQueue,最好避免完全由您自己处理AutoResetEvent。相反,创建一个包来包装ConcurrentQueue并使用它——它可以完成您所需要的一切。如果您只是使用无参数构造函数创建一个BlockingCollection,它无论如何都会为您创建一个ConcurrentQueue

编辑:如果你真的想继续使用AutoResetEvent,那么WaitOne会自动自动重置事件-这是AutoResetEvent的自动部分。将此与ManualResetEvent进行比较,ManualResetEvent不会重置事件。

如果使用.NET 4中的ConcurrentQueue,最好避免完全自己处理自动重置事件。相反,创建一个包来包装ConcurrentQueue并使用它——它可以完成您所需要的一切。如果您只是使用无参数构造函数创建一个BlockingCollection,它无论如何都会为您创建一个ConcurrentQueue

编辑:如果你真的想继续使用AutoResetEvent,那么WaitOne会自动自动重置事件-这是AutoResetEvent的自动部分。将此与ManualResetEvent进行比较,ManualResetEvent不会重置事件。

执行此操作时,queueNotifier.Set事件将发出信号。当发出事件信号并从另一个线程调用_queueNotifier.WaitOne时,两件事同时发生,即在内核模式下:

自事件自动重置后,该事件变为未标记 调用WaitOne的线程已解除阻止 因此,您不必自己显式设置事件状态

然而,正如Jon所说,如果您对共享变量所做的唯一事情就是从队列中推拉项目,那么简单地使用BlockingCollection就更方便了

如果您正在访问多个共享变量,那么有一个您自己的单线程同步机制可能是有意义的

此外,在我看来,如果您要使用自己的代码,最好执行以下操作:

while (_socket.Connected)
{
    _queueNotifier.WaitOne();
    while (!_queue.IsEmpty)
    {
        Data data;
        if (_queue.TryDequeue(out data))
        {
            //handle the data
        }
    }
}
这样,您就不必进入内核模式来设置事件,只要在使用者函数繁忙时将项目添加到队列中。在消费函数的每次迭代中,您还可以避免进入内核模式

确实,对于后者,避免上下文切换是以添加_queue.i空测试为代价的,在该测试中,一个糟糕的实现可能会执行上下文切换;然而,这可能是作为一个互锁的比较交换操作实现的,它不需要进入内核模式

免责声明:我没有检查源代码或IL以验证上述信息。

当您执行queueNotifier.Set时,事件将变为信号。当发出事件信号并从另一个线程调用_queueNotifier.WaitOne时,两件事同时发生,即在内核模式下:

自事件自动重置后,该事件变为未标记 调用WaitOne的线程已解除阻止 因此,您不必自己显式设置事件状态

然而,正如Jon所说,如果您对共享变量所做的唯一事情就是从队列中推拉项目,那么简单地使用BlockingCollection就更方便了

如果您正在访问多个共享变量,那么有一个您自己的单线程同步机制可能是有意义的

此外,在我看来,如果您要使用自己的代码,最好执行以下操作:

while (_socket.Connected)
{
    _queueNotifier.WaitOne();
    while (!_queue.IsEmpty)
    {
        Data data;
        if (_queue.TryDequeue(out data))
        {
            //handle the data
        }
    }
}
这样,您就不必进入内核模式来设置事件,只要在使用者函数繁忙时将项目添加到队列中。在消费函数的每次迭代中,您还可以避免进入内核模式

确实,对于后者,避免上下文切换是以添加_queue.i空测试为代价的,在该测试中,一个糟糕的实现可能会执行上下文切换;然而,这可能是作为一个互锁的比较交换操作实现的,它不需要进入内核模式


免责声明:我没有检查源代码或IL来验证上述信息。

我会检查,但我仍然有兴趣了解AutoResetEvent如何工作,以便在将来再次需要时进一步了解它。@Prix:已编辑以包含该信息。有关更多信息,请参阅AutoResetEvent的文档。感谢您的更新,关于您刚开始所说的,我对将concurrentqueue包装在blockingcollection中有点困惑,使用blockingcollection是否更容易?如果您可以,我希望能提供一些示例,以便更好地理解您的意思…@Prix:BlockingCollection总是包装另一个集合-但是如果您只是创建一个新的BlockingCollection而没有指定要包装的集合,它将自动使用ConcurrentQueue。我建议您阅读BlockingCollection的文档,其中给出了如何使用它的示例等。我将对此进行检查,但我仍然有兴趣了解AutoResetEvent如何工作
如果我将来再次需要它,请进一步了解它。@Prix:已编辑以包含该信息。有关更多信息,请参阅AutoResetEvent的文档。感谢您的更新,关于您刚开始所说的,我对将concurrentqueue包装在blockingcollection中有点困惑,使用blockingcollection是否更容易?如果您可以,我希望能提供一些示例,以便更好地理解您的意思…@Prix:BlockingCollection总是包装另一个集合-但是如果您只是创建一个新的BlockingCollection而没有指定要包装的集合,它将自动使用ConcurrentQueue。我建议您阅读BlockingCollection的文档,其中给出了如何使用它的示例等。
public void MoreData(Data example)
{
    var queueWasEmpty = _queue.IsEmpty;
    _queue.Enqueue(example);
    if (queueWasEmpty) {
        _queueNotifier.Set();
    }
}

private void _SimpleThreadWorker()
{
    while (_socket.Connected)
    {
        _queueNotifier.WaitOne();
        Data data;
        while(!queue.IsEmpty) {
            if (_queue.TryDequeue(out data))
            {
                //handle the data
            }
        }
    }
}