collections被修改; 枚举操作可能无法执行。 锁在哪里可用?

这是一个只有我正在编写和使用的小程序。

现在我要编写所有使用导致此问题的hashset的区域的代码

我不明白这是怎么可能的。 此项目仅在MainWindow中使用

hsProxyList是一个哈希集

HashSet hsProxyList = new HashSet(); 

错误发生在下面的迭代中

  lock (hsProxyList) { int irRandomProxyNumber = GenerateRandomValue.GenerateRandomValueMin(hsProxyList.Count, 0); int irLocalCounter = 0; foreach (var vrProxy in hsProxyList) { if (irLocalCounter == irRandomProxyNumber) { srSelectedProxy = vrProxy; break; } irLocalCounter++; } } } 

我使用hsProxyList的其他地方

我在计算时没有锁定对象 – 我想这不会导致任何错误,但可能不正确 – 不重要

  lblProxyCount.Content = "remaining proxy count: " + hsProxyList.Count; 

 lock (hsProxyList) { hsProxyList.Remove(srSelectedProxy); } 

 lock (hsProxyList) { hsProxyList = new HashSet(); foreach (var vrLine in File.ReadLines(cmbBoxSelectProxy.SelectedItem.ToString())) { hsProxyList.Add(vrLine); } } 

可以看出我到处都在使用锁。 这是一个multithreading软件。 所有hsProxyList都在MainWindow.xaml.cs中使用 – 它是一个C#WPF应用程序

问题出在你所拥有的地方

 lock (hsProxyList) { hsProxyList = new HashSet(); // etc } 

所有锁都在特定对象上,但是当您执行hsProxyList = new HashSet();时,您正在更改对象hsProxyList = new HashSet(); 所以变量hsProxyList引用的对象不再被锁定。

这里有两个问题。 第一个,已经指出的是你在锁定哈希集的同时也将对象hsProxyList指向更改为:

 lock (hsProxyList) { hsProxyList = new HashSet(); // hsProxyList is no longer locked. } 

第二个(也是更微妙的)问题是,你假设Count不需要锁定。 这不是一个安全的假设。 首先,您不知道HashSet如何实现它。 Count是O(1)操作的事实表明存在跟踪计数的成员变量。 这意味着在AddRemove必须更新此变量。 Add的实现可能类似于:

 bool Add( T item ) { this.count++; // Point A. addItemToHashSet(item); } 

请注意, count变量会增加, 然后添加项目。 如果调用Add的线程在A点被中断并且你的另一个调用Count线程被执行,你将收到一个高于实际元素countcount已经递增,但addItemToHashSet没有)。

这可能没有任何严重的后果,但如果你迭代Count元素,它可能会导致崩溃。 调用Remove时也可能出现类似的行为。