收集被修改;不能执行枚举操作.锁在任何可能的地方都被使用

本文关键字:任何可 修改 不能 执行 操作 枚举 | 更新日期: 2023-09-27 18:15:30

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

现在我要编写所有区域的代码,我使用了导致这个问题的哈希集

我不明白这怎么可能。此项仅在主窗口

中使用。

hsProxyList是一个哈希集

  HashSet<string> hsProxyList = new HashSet<string>();

错误发生在下面的迭代

 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<string>();
    foreach (var vrLine in File.ReadLines(cmbBoxSelectProxy.SelectedItem.ToString()))
    {
        hsProxyList.Add(vrLine);
    }
}

可以看出我到处都在使用锁。这是一个多线程软件。所有hsProxyList都在mainwindow . example .cs中使用-它是一个c# WPF应用程序

收集被修改;不能执行枚举操作.锁在任何可能的地方都被使用

问题出在

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

所有的锁都在一个特定的对象上,但是当你做hsProxyList = new HashSet<string>();时,你改变了对象,所以变量hsProxyList所引用的对象不再被锁定。

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

lock (hsProxyList)
{
    hsProxyList = new HashSet<string>();
    // 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的线程,您将收到一个高于实际元素数量的计数(count增加了,但addItemToHashSet没有增加)。

这可能不会产生任何严重的后果,但是如果在Count元素上迭代,则可能导致崩溃。在调用Remove时也可能出现类似的行为。