正确使用.NET Concurrent Collections

时间:2012-11-11 15:40:56

标签: c# .net multithreading .net-4.0 concurrency

在我尝试创建并发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();
}

当一个不同的线程迭代/出列一个危险的东西时,是否正在向ConcurrentQueue添加项目?

根据我的理解,许多同步集合只是单独同步的方法,但concurrentQueue和类似集合的情况是一样的吗?(ConcurrentBagConcurrentDictionary,{{1 }})

4 个答案:

答案 0 :(得分:4)

只要你没有改变作为元素存储的数组,ConcurrentQueue本身就没问题。

但是,使用ManualResetEvent的使用模式表明有更好的解决方案:如果您使用BlockingCollection<T>,则可以避免进行手动同步。

答案 1 :(得分:2)

  

将一个项目添加到ConcurrentQueue,而另一个线程正在迭代/出列它是一件危险的事情吗?

不,这是安全的。

答案 2 :(得分:1)

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();
    }
}

这样的事件序列将导致忽略排队的消息。要么使用其他海报建议的BlockingCollection,要么使用信号量进行信号/等待。

答案 3 :(得分:0)

并发集合旨在保证线程安全。使用它们可以自己实现它们,从而为您节省很多麻烦。

请注意,集合本身是同步的,而不是其中的数据。更新集合中的对象而不关注其他线程会带来竞争条件。

与任何类的使用一样,如果您了解集合的用法和用例,它会有所帮助