简体   繁体   English

正确使用.NET Concurrent Collections

[英]Proper use of .NET Concurrent Collections

In my attempt to create concurrent Socket operations, I've created the following code: 在我尝试创建并发Socket操作时,我创建了以下代码:

ConcurrentQueue<byte[]> messageQueue;
ManualResetEvent resetEvent;
Thread outThread;   // -> new Thread(BeginSending);

public void BeginSending() // invoked by outThread
{
    while (true)
    {
        resetEvent.WaitOne();
        while (messageQueue.Count > 0)
        {
            byte[] msg;
            messageQueue.TryDequeue(out msg);
            // send msg via socket
        }
        resetEvent.Reset();
    }
}

public void QueueMessage(byte[] msg) // invoked by the main thread
{
    messageQueue.Enqueue(msg);
    resetEvent.Set();
}

Is adding items to the ConcurrentQueue while a different thread is iterating/dequeuing it a dangerous thing? 将项目添加到ConcurrentQueue而另一个线程迭代/出列是危险的事情?

From my understanding many synchronized collections simply have individually synchronized methods, but is the same true for concurrentQueue and similar collections? 根据我的理解,许多同步集合只是单独同步的方法,但对于concurrentQueue和类似的集合是一样的吗?
( ConcurrentBag , ConcurrentDictionary , ConcurrentStack ) ConcurrentBagConcurrentDictionaryConcurrentStack

The ConcurrentQueue itself is OK, as long as you are not mutating the arrays stored as its elements. ConcurrentQueue本身没问题,只要你没有改变存储为其元素的数组。

However, your usage pattern with ManualResetEvent suggests that there is a better solution: if you use BlockingCollection<T> , you would be able to avoid doing manual synchronization. 但是,使用ManualResetEvent的使用模式表明有更好的解决方案:如果使用BlockingCollection<T> ,则可以避免进行手动同步。

Is adding items to the ConcurrentQueue while a different thread is iterating/dequeuing it a dangerous thing? 将项目添加到ConcurrentQueue,而另一个线程迭代/出列是危险的事情?

No, it is safe. 不,这很安全。

The ConcurrentQueue is fine, the ManualResetEvent is not: ConcurrentQueue很好,ManualResetEvent不是:

public void BeginSending() // invoked by outThread
{
    while (true)
    {
        resetEvent.WaitOne();
        while (messageQueue.Count > 0)
        {
            byte[] msg;
            messageQueue.TryDequeue(out msg);
            // send msg via socket
        }

    // context change
    messageQueue.Enqueue(msg);
    resetEvent.Set();
    // context change

        resetEvent.Reset();
    }
}

Such a sequence of events will result in an enqueued message being ignored. 这样的事件序列将导致忽略排队的消息。 Either use a BlockingCollection, as suggested by the other posters, or use a semaphore for signal/wait. 要么使用其他海报建议的BlockingCollection,要么使用信号量进行信号/等待。

The concurrent collections are designed to be thread safe. 并发集合设计为线程安全的。 Using them saves you a lot of trouble by implementing them yourself. 使用它们可以自己实现它们,从而为您节省很多麻烦。

Be aware though that the collection itself is synchronized, NOT the data inside it. 请注意,集合本身是同步的,而不是其中的数据。 Updating the objects inside the collections without attention for the other threads can bring race-conditions. 更新集合中的对象而不关注其他线程可能会带来竞争条件。

As with any usage of a class it helps if you have a understanding of the use and use-cases of the collections 与任何类的使用一样,如果您了解集合的用法和用例,它会有所帮助

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM