2009-01-10 19 views
3

在C#中執行線程同步時,我應該在讀取一個值還是僅僅改變它時鎖定一個對象?讀取值時應該鎖定資源嗎?

例如我有隊列<T>對象。我應該在執行Enqueue和Dequeue時將其鎖定,還是應該在檢查Count等值時鎖定它?

回答

3

從MSDN:

隊列<(中<(T>)>)可以支持 多個讀者同時,只要 作爲收集不被修改。 儘管如此,通過 集合列舉本質上不是線程安全的過程。爲了保證枚舉期間線程安全, 可以在整個枚舉過程中鎖定收集。爲了允許 集合被多個 線程讀取和寫入,您的 必須實現您自己的 同步。

你應該確保沒有閱讀器處於活動狀態,而一個項目排隊(鎖定可能是一個好主意)。

看反射器中的計數顯示從私人領域讀取。這可以取決於你對價值做什麼。這意味着你不應該做這樣的事情(沒有適當的鎖定):

if(queue.Count > 0) 
    queue.Dequeue(); 
2

取決於你想要用鎖來做什麼。通常這種鎖定需要一個讀寫器鎖定機制。

讀者/作者鎖定意味着讀者共享一個鎖,所以你可以讓多個讀者同時讀取這個集合,但是要寫,你應該獲得一個排他鎖。

0

CLR保證原子讀取的值高達處理器的寬度。所以如果你在32位上運行,閱讀int將是原子性的。如果你在64位機器上運行,閱讀long將是原子性的。 Ergo,如果CountInt32則不需要鎖定。

This post與您的問題有關。

+0

讀取int可能是原子的,但計算計數可能不一定是原子的。這不僅僅是讀一個整數。它需要一個函數調用,可能還有其他的東西。 – 2009-01-10 15:47:56

+0

Count最可能是一個屬性,它對應於一個隱式函數調用。 – 2009-01-10 15:50:02

1

如果你沒有鎖定它,你可能會得到一個較舊的值。可能會發生競態條件,使得執行寫入操作時更改Count,但在更改之前您將獲得值。例如,如果隊列只有一個項目,並且一個線程調用了出隊,另一個線程可能會讀取該計數,找到它仍然爲1,並再次呼叫出隊。第二次調用在授予鎖定之前不會完成,但在那個時候隊列實際上是空的。