2016-05-11 59 views
0

已編寫下面的代碼以創建由列表組成的數組池。我想稍後以並行方式使用它。要創建池,我想通過預先填充的模板進行復制。 使用模板創建ConcurrentBag

List<candle>[] sourceCandleList = new List<candle>[3]; 
// populate sourceCandleList here with data 
ConcurrentBag<List<candle>[]> poolList = new ConcurrentBag<List<candle>[]>(); 
int maxThreads = 64; 
for (int i = 0; i < maxThreads; i++) 
{ 
    poolList.Add(sourceCandleList); 
} 

這是否創建sourceCandleList的64個深層副本?如果不是,ConcurrentBag仍然是線程安全的嗎?
我不確定的原因是因爲ConcurrentBag中的所有列表似乎都是空的,如果我清除sourceCandleList就像sourceCandleList.Clear()

+2

concurrentbag的實例是線程安全的。沒有更改您存儲的對象實例的線程安全性。不,在add方法中沒有魔法,沒有深拷貝或淺拷貝操作被執行。 – rene

+1

是不同的線程將使用'List []','List '或'candle'的相同實例嗎? –

+0

@rene但我添加了相同的對象64次。 – Manngo

回答

1

ConcurrentBag本身仍然是線程安全的,但是這個代碼最終只是添加了64個指向包的所有引用相同List對象的指針。這是相同的數組添加64次,所以任何對一個數組進行的更改都會發生在所有這些數組上。

您需要手動爲每個數組,每個數組中的每個列表以及每個蠟燭(如果這是一個類而不是不可變的結構體)進行深層複製。它最終會看起來像:

for (int i = 0; i < maxThreads; i++) 
{ 
    List<candle>[] candleList = new List<candle>[3]; 
    for (int j = 0; j < 3; j++) 
    { 
     candleList[j] = new List<candle(); 
     foreach (candle c in sourceCandleList[j]) 
      candleList[j].Add(new candle(c.field1,c.field2)); // If it's an immutable struct, you should be able to just .Add(c) 
    } 
    poolList.Add(candleList); 
} 

你也許可以做到這一點jiggier使用LINQ,但我不知道你正在運行的.NET版本。

+1

@Manngo大聲笑我也無法迴應你的評論,但不,ConvertAll會製作一個新的列表,但是項目將是相同的(假設蠟燭是一個對象)。你最安全的選擇就是實例化一個新的蠟燭。 – zfrank

+0

只是爲了好玩,後續:我確信這個解決方案是絕對正確的,因爲在實施它之後,我的內存不足:-)。但這是一個全新的故事......我只是改成了x64,現在正在測試。非常感謝! – Manngo

0

@zfrank 對不起,我無法發表評論。
下面是否也會創建一個深層副本的技巧?在我的理解ConvertAll創建一個深層複製。

for (int i = 0; i < maxThreads; i++) 
    { 
     List <candle>[] CandleList = new List<candle>[sourceCount]; 
     for (int w = 0; w <= sourceCount - 1; w++) 
      { 
       CandleList[w] = sourceCandleList[w].ConvertAll(c => c); 
      } 
      poolList.Add(CandleList); 
     } 
+1

不,''.ConvertAll(c => c)'會創建列表的淺表副本。但是,這並不重要,因爲每個列表都是空的,因此列表是淺表還是深層副本並不重要。 –