【问题标题】:Proper use of .NET Concurrent Collections正确使用 .NET 并发集合
【发布时间】:2012-11-11 15:40:55
【问题描述】:

在尝试创建并发 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 和类似集合也是如此吗?
ConcurrentBagConcurrentDictionaryConcurrentStack

【问题讨论】:

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


    【解决方案1】:

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

    但是,您对ManualResetEvent 的使用模式表明存在更好的解决方案:如果您使用BlockingCollection&lt;T&gt;,您将能够避免手动同步。

    【讨论】:

    • ManualResetEvent 不合适,无法可靠工作。
    【解决方案2】:

    在另一个线程迭代/出队时将项目添加到 ConcurrentQueue 是否危险?

    不,这是安全的。

    【讨论】:

      【解决方案3】:

      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,或者使用信号量进行信号/等待。

      【讨论】:

      • 嗯,这是一个有趣的想法。在调用WaitOne() 之前简单地添加支票怎么样,例如:if (messageQueue.Count == 0) resetEvent.WaitOne();。这还不够吗?
      • @Acidic - 也许,对于单个生产者和单个消费者来说是的,但是为什么要麻烦呢? BlockingCollection 或使用 Semaphore 代替 MRE 肯定会为任意数量的生产者/消费者正常工作。 MRE 确实有其用途,但生产者-消费者队列不是其中之一。
      【解决方案4】:

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2012-07-31
        • 2011-03-09
        • 1970-01-01
        • 2023-03-20
        • 2014-01-16
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多