3

在我尝试创建并发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类似的集合来说也是如此吗?
( ConcurrentBag, ConcurrentDictionary, ConcurrentStack)

4

4 回答 4

4

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

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

于 2012-11-11T15:46:18.167 回答
2

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

不,这是安全的。

于 2012-11-11T15:43:00.020 回答
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,或者使用信号量进行信号/等待。

于 2012-11-11T19:14:31.933 回答
0

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

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

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

于 2012-11-11T15:46:34.750 回答