Коллекция была изменена; операция перечисления может не выполняться. Блокировка используется везде, насколько это возможно?
Это небольшая программа, которую я пишу и использую только.
Теперь я собираюсь написать код всех областей, где я использую hashset, вызвавший эту проблему.
Я не понимаю, как это возможно. Этот элемент используется только в MainWindow
hsProxyList - это hashset
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.xaml.cs - это приложение WPF для С#
Ответы
Ответ 1
Проблема заключается в том, что у вас
lock (hsProxyList)
{
hsProxyList = new HashSet<string>();
// etc
}
Все блокировки находятся на определенном объекте, однако вы меняете объект, когда вы выполняете hsProxyList = new HashSet<string>();
, поэтому объект, к которому относится переменная hsProxyList, больше не заблокирован.
Ответ 2
Здесь есть две проблемы. Первое, что уже было указано, заключается в том, что вы блокируете хэш-набор, одновременно меняя объект hsProxyList
на:
lock (hsProxyList)
{
hsProxyList = new HashSet<string>();
// hsProxyList is no longer locked.
}
Вторая (и более тонкая) проблема заключается в том, что вы предполагаете, что Count
не требует блокировки. Это не безопасное предположение. Во-первых, вы не знаете, как HashSet
его реализовала. Тот факт, что Count является операцией O(1)
, указывает, что существует переменная-член, которая отслеживает счет. Это означает, что на Add
или Remove
эта переменная должна быть обновлена. Реализация Add
может выглядеть примерно так:
bool Add( T item ) {
this.count++;
// Point A.
addItemToHashSet(item);
}
Обратите внимание, что переменная Count
увеличивается, а затем добавляется элемент. Если поток, вызывающий Add
, перехвачен в точке A, и выполняется ваш другой поток, который вызывает Count
, вы получите счетчик, который больше, чем число фактических элементов (Count
был incremented, но addItemToHashSet
не имеет).
Это может не иметь серьезных последствий, но если вы повторяете элементы Count
, это может привести к сбою. Подобное поведение также возможно при вызове Remove
.