是使用运算符“=”线程安全(C#)</t>复制整个队列<t>

时间:2012-02-13 17:31:20

标签: c# collections thread-safety

我有通用Queue<T>System.Collections.Generic),可以从一个线程进行写入。并且必须从另一个线程访问它才能阅读。

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

这是一些伪代码:

//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:非常感谢,我不知道这只是复制链接。那么有没有办法以线程安全的方式按值复制整个对象?

5 个答案:

答案 0 :(得分:11)

Queue<T>是参考类型。因此,将queue1分配给queue2只会复制引用,而不是队列本身。

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

我相信ConcurrentQueue<T>使用“无锁”编程技术(Interlocked.Exchange和朋友)并且非常快。在排除它作为解决方案之前,您应首先对其进行基准测试。

复制Queue<T>肯定比使用ConcurrentQueue<T>慢。


在我的2.6GHz系统上ConcurrentQueue<object>每秒管理1500万个入队/出队对,而使用Queue<object>则为4000万。所以Queue<object>大约快三倍。

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

答案 1 :(得分:2)

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

答案 2 :(得分:1)

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

请注意,您并未复制队列本身:您正在复制对单个队列的引用。 (引用赋值是原子的,所以你的queue2 = queue1行不是问题。这是你随后对非线程安全的队列所做的事情。)

答案 3 :(得分:0)

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

如果您打算进行深层复印。看到this帖子可以帮助您执行对象的深层复制。虽然@CodeInChaos有一个非常好的观点。以这种方式复制整个对象肯定比使用ConcurentQueue<T>慢。

答案 4 :(得分:0)

以下是MSDN关于线程安全的说法:

  

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