2012-11-29 87 views
2

我有一個ReadOnlyCollection一個高度線程化的應用程序如下:ReadOnlyCollections和線程 - 此代碼是否安全?

internal static ReadOnlyCollection<DistributorBackpressure44> DistributorBackpressure44Cache 
{ 
    get 
    { 
     return _distributorBackpressure44; 
    } 
    set 
    { 
     _distributorBackpressure44 = value; 
    } 
} 

我在此集合被替換(總是在一個單獨的線程)的應用程序一個地方,它看起來像這樣:

CicApplication.DistributorBackpressure44Cache = new ReadOnlyCollection<DistributorBackpressure44>(someQueryResults.ToList()); 

我有許多地方在代碼中訪問這個集合,通常通過Linq查詢,在許多不同的線程中。代碼通常看起來像這樣:

foreach (DistributorBackpressure44 distributorBackpressure44 in CicApplication.DistributorBackpressure44Cache.Where(row => row.Coater == coater && row.CoaterTime >= targetTime).ToList()) 
{ 
... 
... 
} 

我假設我在做什麼是線程安全的,而不需要做任何鎖定?我不確定上面的查詢會發生什麼,如果它發生在集合在不同線程中被替換的同時發生?

回答

5

引用賦值是原子的,所以是的,它是線程安全的。但是隻要你不依賴數據準備在寫入後立即被讀取。這是因爲緩存,你可能想要拋出一個volatile來防止這種情況。請參閱reference assignment is atomic so why is Interlocked.Exchange(ref Object, Object) needed?

+0

我不確定你的意思。但是,如果您的意思是某些數據讀者可能擁有「舊」副本,而某些讀者可能擁有「新副本」,則這是可以接受的。 –

+0

你明白正確,省略了volatile部分。 –

2

這是不可能的。在完全不可預測的時刻,在線程分配屬性後,其他線程將看到新的集合。在此之前他們會讀取陳舊的值。其中可能爲空或可能是具有完全不同內容的另一個集合。

隨機性是什麼會讓你陷入困境。請注意,這與集合是否爲ReadOnly無關。也許線程使用陳舊的值是可以的,但這並不常見。大多數你沒有提到它是好的,所以你可能還沒有考慮到後果。你需要考慮這一點。在屬性獲取者和設置者中你無法對自己做任何事情,線程將不得不自己進行談判。這是什麼使得線程,並使得你徹底分析代碼中共享可變數據的地方非常重要。像這個屬性一樣。

0

聽起來好像它不會成爲你的問題,但如果ReadOnlyCollection包裝的底層集合發生變化,你可能會遇到問題。

例如,下面的代碼塊將引發與所述消息的InvalidOperationException「集合被修改;枚舉操作可能不執行」,因爲底層List<int>具有從它除去的物品而被列舉過來在另一個線程上。

var numbers = new List<int>() {1,2,3,4,5}; 
var readOnly = new ReadOnlyCollection<int>(numbers); 

ThreadPool.QueueUserWorkItem(x => { 
    foreach (int number in readOnly) 
    { 
     Console.WriteLine(number); 
     Thread.Sleep(300); 
    } 
}); 

Thread.Sleep(150); 
numbers.Remove(2);