2011-05-03 83 views
3
private List<T> _T; 
    private readonly object _syncLock = new object(); 

    private List<T> MyT 
    { 
     get 
     { 
      lock (_syncLock) 
       return _T.ToList<T>(); 
     } 
     set 
     { 
      lock (_syncLock) 
       _T = value; 
     } 
    } 
+0

精確重複數據刪除:http://stackoverflow.com/questions/5874317/thread-safe-listt-property – 2011-05-03 19:52:18

+0

下,你將不會被更新當前值的假設,可以按如下方式解決這個問題基於當前值...是的,這是有點線程安全的。但是,如果您有任何看起來像「myTSObj.MyT = myTSObj.MyT + 1」的代碼,那麼不......實際上並非如此。在這種情況下,你已經打開了自己的比賽條件。 – 2011-05-03 19:52:34

+0

我認爲這是安全的,修改原始列表將修改ToList()所做的副本,而不是原始副本。那將被分配爲新成員。 – 2011-05-03 19:57:16

回答

2

不,它不是線程安全的。看下面的代碼:

static MyClass<int> sharedInstance = ...; 

// Create a list 
var list = new List<int>(); 

// Share the list 
sharedInstance.MyT = list; 

// list is now shared, this call is not thread-safe. 
list.Add(5); 

問題是你允許消費者有一個內部數據結構的引用。

private List<T> MyT 
{ 
    get 
    { 
     lock (_syncLock) 
      return _T.ToList<T>(); 
    } 
    set 
    { 
     var copy = value.ToList(); 

     lock (_syncLock) 
      _T = copy; 
    } 
} 
+0

你需要鎖定設置嗎?因爲它只是一個參考作業 – 2015-01-12 05:18:00

+0

@EpiX:嚴格地說不是。有一個鎖的好處是它增加了一個內存屏障。這會清除緩存並阻止其他線程獲取舊的(已緩存的)引用。因此,即使在調用set之後,它也可以防止其他線程獲得舊值。但是由於'get'已經使用'lock','set'中的'lock'是多餘的。不過,我喜歡在set和get中使用lock,因爲在大多數情況下這是必需的,並且使得代碼在這種情況下更容易混淆。如果我們要從'set'中移除'lock',我們將不得不明確地評論爲什麼'lock'不是必需的 – Steven 2015-01-12 13:39:07

2

是的。你使用了一個成員變量作爲鎖,並確保它不能被更改。這將工作正常。

+1

然而,你仍然可以有競爭條件。 – 2011-05-03 19:54:07

+0

究竟如何?這是一個列表,而不像你的其他評論中的那樣。 – Nik 2011-05-03 19:55:39

+0

是真的,但這個想法還是一樣的。假設您的邏輯將項目添加到列表中,如果項目尚不存在於列表中。但是,運行相同邏輯的另一個線程也會執行相同的操作。有可能多次獲得相同的值。爲了避免這種情況,你的*邏輯*應該鎖定對象不可能避免像這樣的所有情況。 – 2011-05-03 19:57:25

1

是的,你似乎很安全。如果你看一下ToList()的定義,它是:

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) 
{ 
    if (source == null) 
    { 
     throw Error.ArgumentNull("source"); 
    } 
    return new List<TSource>(source); 
} 

所以基本上你正在創建其中包含了舊錶的元素的新名單,所有在你提供給它線程安全的鎖。

現在,列表中的內容將與這兩個列表中的相同引用相同,因此它不會保護您改變列表中存儲的原始對象,它僅保護列表本身。

+0

沒關係。我使用它的值類型。 – Xaqron 2011-05-03 20:08:30

+0

通過查看'ToList ()'方法,您無法總結解決方案是線程安全的。實際上,當爲這個方法提供一個實例時,在下面修改它會破壞它(查看列表 .ctor)。看到我的答案。在這裏,我舉例說明如何引入競爭條件。 – Steven 2011-05-03 21:00:24