2010-07-28 48 views
2

我有一個有幾個數組列表的類。在線程應用程序中使用C#揮發性關鍵字

我的主類創建了這個類的新實例。我的主課有至少2個線程,在我的班級中添加和刪除其中的數組列表。目前,一切都運行良好,但我只是想知道,如果這將是更安全的聲明,我用的ArrayList類是揮發性如/

private volatile myclass; 
myclass = new myclass(); 
...... 
myclass.Add(...) 
myclass.Clear(..) 
+1

易失性僅適用於字段 – Kimi 2010-07-28 08:02:29

+0

爲什麼你想使易失性?它會給你的應用程序增加任何價值嗎? – Shekhar 2010-07-28 08:04:24

+1

現在回答你的問題,並接受它。您的問題中幾乎90%都會回答您的問題。 – Incognito 2010-07-28 08:04:45

回答

4

在這個例子中,使用volatile關鍵字不會使你的代碼是線程安全的。 volatile關鍵字通常用於確保在讀取或寫入變量的值(即類字段)時,該變量的最新值要麼從主內存中讀取,要麼直接寫入主內存,而不是從緩存中讀取(例如,例如一個CPU寄存器)。 volatile關鍵字是一種說法:「不要對此共享字段使用緩存優化」,並且可以消除線程可能使用字段本地副本而不能看到彼此更新的問題。

在你的情況下,myclass的值實際上並沒有被更新(即你沒有重新分配myclass),所以volatile對你沒有用,而且它不是你實際想要創建線程的myclass變量的更新無論如何,在這種情況下都是安全的。

如果您希望更新實際的類線程安全,那麼圍繞「添加」和「清除」使用「鎖定」是一個直接的選擇。這將確保一次只有一個線程可以執行這些操作(它更新myclass的內部狀態),因此不應該並行執行。

鎖可以使用如下:

private readonly object syncObj = new object(); 
private readonly myclass = new myclass(); 
...... 

lock (syncObj) 
{ 
    myclass.Add(...) 
} 

lock (syncObj) 
{ 
    myclass.Clear(..) 
} 

您還需要添加讀取正被「添加」,如果是這樣的話,雖然它沒有更新了狀態的任何代碼鎖定各地出現在您的示例代碼中。

首次編寫多線程代碼時可能並不明顯,爲什麼添加到集合時需要鎖定。如果我們以List或ArrayList爲例,那麼問題就出現了,因爲這些集合在內部使用一個數組作爲後備存儲,並且將動態「增長」這個數組(即通過創建一個新的更大的數組並且複製舊的內容)調用Add時會滿足容量。這一切都發生在內部,需要維護此數組和變量,例如集合的當前大小(而不是實際數組的大小可能更大)。因此,如果內部數組需要增長,那麼添加到集合中可能涉及多個步驟。當以不安全的方式使用多個線程時,多個線程可能間接導致在添加時發生增長,並因此踐踏所有其他更新。除了同時添加多個線程的問題外,還有另一個線程可能正在嘗試讀取集合,同時內部狀態正在更改的問題。使用鎖確保像這樣的操作在不受其他線程干擾的情況下完成。

+0

把鎖放在像你說的或鎖定的對象周圍是更好的辦法(這個)。當使用鎖並且另一個線程嘗試訪問它時發生了什麼。它只是坐在他們的等待? – Jon 2010-07-28 09:30:21

+0

@Jon **問題** 1:最好鎖定一個私有鎖變量而不是「this」,因爲「this」對任何有該類實例引用的人都是可見的,即類外部的線程可以鎖定對實際上是同一事物的類的引用。這是使用「this」的意想不到的結果。 – 2010-07-28 09:51:28

+0

@Jon **問題** 2:當一個線程試圖進入一個忙碌的鎖定部分(這稱爲鎖定爭用),實際上該線程被掛起,然後當鎖定變爲空閒時喚醒。如果有多個線程在等待,則只有一個線程會成功,其餘線程將再次掛起。實際的鎖定檢查和鎖定非常快,當鎖定不被爭用時,即繁忙。儘量保持鎖內的代碼有效,但是當多線程時,正確性和可讀性非常重要。在嘗試優化地獄之前獲得正確性和單元測試。 – 2010-07-28 09:54:39

2

目前,該代碼是錯誤的;添加一個volatile關鍵字不會解決它。在線程中使用.NET類而不添加同步並不安全。

如果不知道更多關於代碼結構的信息,很難給出直接的建議。第一步是在所有對列表對象的訪問周圍開始使用lock關鍵字;但是,在代碼中仍然可能存在假設,這些假設在多線程中不起作用。

可以使用已經安全用於多線程訪問的集合類,這可以避免將lock關鍵字置於正確位置,但仍然有可能產生錯誤。

你可以發佈一些更多的代碼嗎?這樣我們可以給出關於使線程安全的更具體的建議。

+0

你知道哪些集合是線程安全的嗎? – Jon 2010-07-28 08:34:14

+0

本頁提供了一個很好的解釋:http://msdn.microsoft.com/en-us/library/573ths2x(VS.90).aspx。但是自己使用線程安全的集合可能不會解決問題;如果你的代碼與我的代碼類似,它將以不安全的方式對項目本身進行處理。 – 2010-07-28 08:40:46

+0

謝謝。本質上講,我的課有幾個數組列表,然後在我的班級中創建了添加/刪除/清除/查找命令,該命令進入相關的數組列表並完成它的工作。但是,我的類的這個實例可能會調用最多2個線程上的添加/刪除。這聽起來像我需要鎖定這個類的實例,只要它被使用。 – Jon 2010-07-28 12:10:11