2011-07-19 75 views
2

操作如果隊列syncronized:隊列同步化,並在C#

var _item = Queue.Synchronized(new Queue()); 

我可以打電話給喜歡加入和離開隊列它的方法,而無需使用鎖語句?

我當前的代碼是:

lock (_item.SyncRoot) 
{ 
    _item.Enqueue(obj); 
} 

我可以線程安全地使用:

_item.Enqueue(obj); 
var item = _item.Dequeue(); 

回答

4

的呼叫Enqueue和調用Dequeue是線程安全的。
但是,您的示例代碼不是:
在呼叫Enqueue和呼叫Dequeue之間可能存在線程切換。這意味着item可能是obj之外的另一個實例,或者對Dequeue的調用會引發異常,因爲它現在爲空。

爲了使您的示例代碼線程安全的,你仍然需要明確地鎖定:

lock(_item.SyncRoot) 
{ 
    _item.Enqueue(obj); 
    var item = _item.Dequeue); 
} 

只是現在得到了保證,這item參考,等於在所有情況下obj

4

這幾乎是什麼SynchronizedQueue做,但有一個問題......你通常需要檢查.Count和一個.Dequeue()原子單位 - 不檢查.Count(一個單元),然後.Dequeue()(另一單位) - 一旦鎖定被投降,你不能相信.Count,如果另一個線程盜取了工作,.Dequeue()將拋出。

也許嘗試ConcurrentQueue<T>在4.0(與.TryDequeue()),或使用Queue<T>lock

2

MSDN

爲了保證 隊列的線程安全的,所有操作必須做 只通過這個包裝。

枚舉整個集合是 本質上不是線程安全的 過程。即使集合是 同步,其他線程仍可以 修改集合,這會導致枚舉器引發 引發異常。 要在枚舉中保證線程安全,您可以在整個 枚舉期間鎖定 集合,或者捕獲由其他 線程所做更改產生的異常 。

正如約翰飛碟雙向的答案表明here,你可能會更好,或者使用鎖定,因爲枚舉可能會導致異常。

Gregs answer也提到了Marc提到的Count不是線程安全的。