【问题标题】:Is copying of entire Queue<T> with operator "=" thread safe (C#)使用运算符“=”线程安全(C#)复制整个 Queue<T>
【发布时间】:2012-03-05 02:56:54
【问题描述】:

我有通用的Queue&lt;T&gt; (System.Collections.Generic),可以从一个线程进行写入访问。并且必须从另一个线程访问才能读取。

出于性能原因,我不想进行任何进程同步(包括使用ConcurrentQueue&lt;T&gt;)。所以我想出了将整个队列复制到读取线程中另一个相同类型的队列对象的想法。读取线程中的后续操作将在副本上完成。复制将使用简单的运算符= 完成。

这是一些伪代码:

//Creating main queue
Queue<MyType> queue1 = new Queue<MyType>();

写作主题:

//Perform writing in the main queue
queue1.Enqueue(object);
...
queue1.Dequeue();

阅读线程:

//Copy main queue 
Queue<MyType> queue2 = queue1;
//perform all operations in reading thread on queue2

那么这样的解决方案线程安全吗?

UPD:非常感谢,我不知道这只是复制链接。那么有没有办法以线程安全的方式按值复制整个对象?

【问题讨论】:

  • 只有在将队列发布到另一个线程后不更改队列时,它才是线程安全的。
  • 通常,Queue 用于生产者/消费者场景。即,一个线程写入它,另一个线程从中读取。每次都复制它没有多大意义(您可以使用任何集合类型,并且它的工作方式相同)。您应该使用单个共享队列并在出列单个项目时立即将其锁定,或者使用ConcurrentQueue,如下所述。

标签: c# collections thread-safety


【解决方案1】:

Queue&lt;T&gt; 是一个引用类型。所以将queue1 分配给queue2 只会复制引用,而不是队列本身。

赋值本身是原子的,因此是线程安全的。在一个线程中访问queue1,在另一个线程中访问queue2 并不比从它们两个线程访问queue1 更安全。即它是不安全的。

我相信ConcurrentQueue&lt;T&gt; 使用“无锁”编程技术(Interlocked.Exchange 和朋友)并且速度非常快。您应该先对其进行基准测试,然后再将其排除为解决方案。

复制Queue&lt;T&gt; 肯定会比只使用ConcurrentQueue&lt;T&gt; 慢。


在我的 2.6GHz 系统上,ConcurrentQueue&lt;object&gt; 每秒管理 1500 万个入队/出队对,而 Queue&lt;object&gt; 管理着 4000 万对。所以Queue&lt;object&gt; 的速度大约是原来的三倍。

一个入队/出队对的 200 个 CPU 周期非常便宜。如果这是瓶颈,请尝试在队列中使用更精细的项目。

【讨论】:

    【解决方案2】:

    这不会复制Queue 的实例。它只复制引用本身。复制引用是原子的,但新引用仍将指向相同的实例。从多个线程修改实例在没有同步的情况下是线程安全的。

    【讨论】:

      【解决方案3】:

      简短回答 -- 不,它不是线程安全的

      请注意,您不是在复制队列本身:您是在复制对单个队列的引用。 (引用分配是原子的,因此您的 queue2 = queue1 行不是问题。这是您随后对根本不是线程安全的队列所做的事情。)

      【讨论】:

        【解决方案4】:

        以下是MSDN 对线程安全的看法:

        一个队列可以同时支持多个读取器,只要集合没有被修改。即便如此,通过集合进行枚举本质上不是线程安全的过程。为了保证枚举过程中的线程安全,可以在整个枚举过程中锁定集合。要允许集合被多个线程访问以进行读写,您必须实现自己的同步。

        【讨论】:

          【解决方案5】:

          以这种方式复制集合只会导致对象的浅拷贝。这意味着它只会将引用复制到同一个队列。这是线程安全的。

          如果您打算进行深层复制。请参阅this 帖子可以帮助您执行对象的深层复制。尽管@CodeInChaos 有一个非常好的观点。以这种方式复制整个对象肯定会比使用ConcurentQueue&lt;T&gt; 慢。

          【讨论】:

          • 那种深拷贝很丑。而且它肯定比只使用ConcurrentQueue&lt;T&gt; 慢。
          • @CodeInChaos - 我知道,但我认为他在帖子中提到他不想使用 ConcurrentQueue,这就是我不建议使用它的原因。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-05-01
          • 2011-05-05
          相关资源
          最近更新 更多