C# 正确使用.NET并发集合

C# 正确使用.NET并发集合,c#,.net,multithreading,.net-4.0,concurrency,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

在尝试创建并发
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消息队列;
手动复位事件复位事件;
线程输出线程;//->新线程(开始发送);
public void BeginSending()//由outThread调用
{
while(true)
{
resetEvent.WaitOne();
while(messageQueue.Count>0)
{
字节[]msg;
messageQueue.TryDequeue(out msg);
//通过套接字发送消息
}
resetEvent.Reset();
}
}
public void QueueMessage(byte[]msg)//由主线程调用
{
messageQueue.Enqueue(msg);
resetEvent.Set();
}
当另一个线程正在迭代/退出队列时,将项目添加到
ConcurrentQueue
是否是一件危险的事情?

据我所知,许多同步的集合只是有单独的同步方法,但是对于
concurrentQueue
和类似的集合也是一样的吗?
ConcurrentBag
ConcurrentDictionary
ConcurrentStack

当另一个线程对ConcurrentQueue进行迭代/出列时,将项目添加到ConcurrentQueue是否是一件危险的事情


不,它是安全的。

只要不改变存储为其元素的数组,
ConcurrentQueue本身就可以了


但是,您对
ManualResetEvent
的使用模式表明有一个更好的解决方案:如果您使用,您将能够避免手动同步。

并发集合的设计是线程安全的。通过自己实现它们,使用它们可以节省很多麻烦

请注意,集合本身是同步的,而不是其中的数据。在不注意其他线程的情况下更新集合中的对象可能会带来争用条件


与类的任何用法一样,如果您了解集合的使用和用例,它会有所帮助。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,或者使用信号灯进行信号/等待。

ManualResetEvent不合适,无法可靠工作。嗯,这是一个有趣的想法。在调用
WaitOne()
之前简单地添加一个检查,类似于:
if(messageQueue.Count==0)resetEvent.WaitOne()。这还不够吗?@acid-也许,对于一个生产者和一个消费者来说是的,但为什么要麻烦呢?对于任何数量的生产者/消费者来说,阻塞集合或使用信号量而不是MRE肯定会正常工作。MRE确实有它的用途,但生产者-消费者队列不在其中。