2012-02-13 19 views
7

我有通用的Queue<T>System.Collections.Generic),它是从一个线程写入访问。它必须从另一个线程访问以供阅读。复制整个队列<T>与运算符“=”线程安全(C#)

出于性能原因,我不想进行任何进程同步(其中包括使用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:非常感谢,我不知道这只是复制链接。那么有没有办法按照线程安全的方式通过值复制整个对象?

+0

只有在您将其发布到另一个线程后不更改队列时,它才是线程安全的。 – Steven 2012-02-13 17:39:07

+0

通常,“Queue”意味着在生产者/消费者场景中使用。也就是说,一个线程写入它,另一个线程读取它。每次复制它都没有什么意义(您可以使用任何集合类型,并且它将工作相同)。您应该使用单个共享队列并在您离队单个项目时很快将其锁定,或者使用下面所述的'ConcurrentQueue'。 – Groo 2012-02-13 18:38:33

回答

11

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

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

我相信ConcurrentQueue<T>使用“无锁”编程技术(Interlocked.Exchange和朋友),速度相当快。您应该首先进行基准测试,然后再将其排除为解决方案。

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


在我的2.6GHz系统ConcurrentQueue<object>管理每秒1500万入队/出队对比例为40万元,与Queue<object>。所以Queue<object>大约是三倍的速度。

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

+0

这是资料。谢谢! – 2012-02-13 17:46:09

1

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

请注意,您并未复制队列本身:您正在将引用复制到单个队列中。 (参考作业是原子性的,因此您的queue2 = queue1行不是问题,这是您随后对非线程安全的队列执行的操作。)

2

这并不复制Queue的实例。它只复制参考本身。复制引用是原子的,但新引用仍将指向相同的实例。从多个线程修改实例是而不是线程安全无需同步。

0

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

如果你的意图是做一个深层复制。查看this发布可以帮助您执行该对象的深层副本。虽然@CodeInChaos有一个非常好的观点。以这种方式复制整个对象肯定比只使用ConcurentQueue<T>慢。

+1

这种深层复制非常难看。它肯定比使用'ConcurrentQueue '慢。 – CodesInChaos 2012-02-13 17:37:03

+0

@CodeInChaos - 我知道,但我认为他在他的帖子中提到他不想使用ConcurrentQueue ,这就是为什么我没有建议。 – TheBoyan 2012-02-13 17:38:07

0

这里是MSDN不得不说的线程安全:

队列可以支持多个读者同时,只要收集不被修改。即便如此,枚举集合本质上不是一个线程安全的过程。为了确保枚举期间的线程安全性,您可以在整个枚举过程中锁定集合。为了让集合可以被多个线程读取和写入,您必须实现自己的同步。