
最近在寫多執行緒的功能有需要用到物件池(object pool)的架構,當然最簡單的想法就是用List<T>搭配LINQ解決。
但測試的時候,偶爾Log會報”集合已修改; 列舉作業可能尚未執行”,第一次看到這段文字有點一頭霧水。
public void Test()
{
foreach (var item in list.Where(x => x.Name == target))
{
//DoSomething...
}
}
多方了解後才知道是在foreach的過程中list被其他執行緒修改導致報錯。
有個簡單的解決方法是在foreach的最後加上ToList(),讓本次foreach時先拷貝一份列表,但內容仍是相同的參考。
只是對已經被pool移除的物件,可能會有例外發生(ex.移除過程被呼叫dispose())的風險。
public void Test()
{
foreach (var item in list.Where(x => x.Name == target).ToList())
{
//DoSomething...
}
}
如果有移除物件的動作,可以將原本的List<T>改成ConcurrentBag<T>或是及其他執行緒安全的結構(偉哉.NET),在物件的存取過程中保證物件的生命週期。
發佈留言