2011-03-31 122 views
1

我有一个嵌套循环‘在我的代码结构’有时候,我得到了以下信息收藏已修改; 。枚举操作可能不会执行”集合元素不被修改

集合被修改;枚举操作可能不会执行。

我有一个集合,我通过循环,如下图所示。CollList<string>

foreach (string[] s1 in obj.Coll 
{ 
    foreach (string s in s1) { } 
} 

对于数组中的每个字符串,我需要ŧ o使用它(读取为读取值,而不是写入)。 我用它做的所有事情就是获取目录(这个值是一个路径)并将这个字符串拆分成一个数组。

这怎么解决?

+1

“有时候”是发生了什么事情的死亡泄露:另一个线程修改了收集。 – Jon 2011-03-31 09:24:14

+0

[C#Collection可能的重复被修改;枚举操作可能不会执行](http://stackoverflow.com/questions/2024179/c-sharp-collection-was-modified-enumeration-operation-may-not-execute) – nawfal 2013-06-05 17:52:25

回答

0

你可以试试:

foreach (string[] s1 in obj.Coll.ToArray()) 
{ 

这将开始迭代之前采取的副本!

+1

请注意,这只会工作,如果集合是没有被另一个线程改变,因为'ToArray()'不是线程安全的。 – mgronber 2011-03-31 13:11:35

+0

我已经在重负载多线程应用程序中使用了多年,没有发生任何错误或问题,您确定吗? – 2011-03-31 15:49:08

+0

我编辑了我的答案来证明问题。 – mgronber 2011-03-31 16:51:56

2

obj.Coll在枚举时发生了变化。如果它没有被当前线程改变,它可能会被其他线程改变。如果集合被当前线程更改,基本上有两种方法可以解决问题:您可以创建集合的副本并枚举副本,或者可以推迟更改,直到枚举集合。

但是,如果集合被另一个线程更改,则应该以线程安全的方式访问集合(不仅在这里,而且在任何地方)。

编辑为基伦斯通:

我写了一个短代码,以证明List<T>.ToArray()不是线程安全的。

var list = new List<int>(); 

Task.Factory.StartNew(() => { 
    for (int i = 0; i < 1000000; ++i) { 
     list.Clear(); 

     // Add values from 1 to 9 
     for (int j = 1; j < 10; ++j) { 
      list.Add(j); 
     } 
    } 

    Console.WriteLine("Thread Exit: list.Add()"); 
}); 

Task.Factory.StartNew(() => { 
    for (int i = 0; i < 100; ++i) { 
     var array = list.ToArray(); 
     if (array.Length > 0) { 
      Console.WriteLine("ToArray(): {0}", string.Join(", ", array)); 
     } 
    } 

    Console.WriteLine("Thread Exit: list.ToArray()"); 
}); 

下面是输出的片段。我想这证明了我的说法。该片段包含15行,其中9个包含错误的数据。

ToArray(): 1, 2, 3, 4 
ToArray(): 1, 2, 3, 4, 5, 0, 0, 0, 0 
ToArray(): 1, 2, 3, 4, 5, 6, 7, 0, 0 
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0, 0 
ToArray(): 1, 2, 3, 4, 5, 0, 0, 0, 0 
ToArray(): 0, 0, 0, 4, 5, 6, 7 
ToArray(): 1, 2, 0, 0, 0, 0, 0, 0, 0 
ToArray(): 1, 2, 3 
ToArray(): 1, 0, 0, 0, 0, 0, 0, 0, 0 
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0 
ToArray(): 1, 2 
ToArray(): 1, 2, 3 
ToArray(): 0, 0, 0, 0, 0, 0, 0, 0 
ToArray(): 1, 2, 3, 4 
ToArray(): 1, 2, 3, 4, 5, 6, 7, 8 

将会有更多的变化,如果我们使用list.Insert(0, j)代替list.Add(j)

相关问题