2012-02-13 50 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不得不說的線程安全:

隊列可以支持多個讀者同時,只要收集不被修改。即便如此,枚舉集合本質上不是一個線程安全的過程。爲了確保枚舉期間的線程安全性,您可以在整個枚舉過程中鎖定集合。爲了讓集合可以被多個線程讀取和寫入,您必須實現自己的同步。