У меня есть следующий словарь:
Dictionary<long, ChangeLogProcess> _changeLogProcesses =
new Dictionary<long, ChangeLogProcess>();
У меня есть метод, который пытается получить следующий changelogprocess в словаре определенного статуса (если нет элементов определенного статуса, он возвращает null):
var changeLogProcesses =
from entry in _changeLogProcesses
where (entry.Value.Status == status)
select entry.Value;
changeLogProcess = changeLogProcesses.FirstOrDefault<ChangeLogProcess>();
Однако во время выполнения он бросает исключение во время запроса linq? Я провела множество тестов, чтобы убедиться, что есть элементы в списке и т.д., Но проблема сохраняется?
Стоит отметить, что этот метод является частью службы, работающей в многопоточной среде. Запрос linq выше (и весь доступ к нему, такой как элементы, добавленные/удаленные в список, или изменения состояния в элементы в списке), все завернуты в блокировки записи ReaderWriterLockSlim. Опять же, я отлаживал его широко, чтобы убедиться, что никогда больше не будет ни одного потока, обращающегося к списку в любое время.
Что может привести к переполнению стека, поскольку это связано с некоторыми возможными другими ошибками, такими как изменение списка во время запроса? (опять же, я только один поток, обращающийся к списку в любой момент времени)
EDIT: в соответствии с запросом код получателя и сеттера:
public ChangeLogProcessStatus Status
{
get { return _status; }
set
{
//more that one place can initiate a retry now, so retry count is handled in the property setter
if (PreviousStatus <= ChangeLogProcessStatus.Waiting && value >= ChangeLogProcessStatus.RetryWaiting)
{
this.ChangeLog.Tries++;
//If it retry waiting, remove this last service machine from the
//list so it can try it again because it not an error
if (value == ChangeLogProcessStatus.RetryWaiting && _previousServiceMachineIds.Count > 0)
{
_previousServiceMachineIds.RemoveAt(_previousServiceMachineIds.Count() - 1);
}
}
PreviousStatus = _status;
_status = value;
}
}
LAST EDIT - я удалил предыдущие примеры, поскольку проблема не существовала в этом коде.
Оказывается, это было в другой части приложения, и было очень сложно найти рекурсию. Было совпадением, что ошибка была повышена во время запроса linq, в результате чего рекурсивно вызывается 420000+ раз.
Все ответы ниже были полезными и на правильном пути к поиску проблемы в многопоточных приложениях, однако в первом ответе определенно подчеркнута рекурсия, как проблема, в которой это оказалось (хотя это не было одним из как и казалось очевидным).
Еще раз спасибо
Спасибо
Проверьте свойство класса ChangeLogProcess, чтобы убедиться, что оно не является саморефлексивным. Это, я думаю, наиболее вероятная причина исключения в этом случае.
Пример:
private ChangeLogStatus status;
public ChangeLogStatus Status
{
get { return this.Status; } // instead of this.status
set { this.status = value }
}
Другой возможной альтернативой является проверка равенства для статуса. Вы переопределили Equals() для ChangeLogStatus? Проверьте там, чтобы убедиться, что у вас нет кода самореференции (или, по крайней мере, способ прекращения рекурсии).
Я заметил, что некоторые коллекции ведут себя очень плохо, когда затрагиваются двумя потоками одновременно.
Фактически вы позволяете нескольким потокам одновременно касаться коллекции. RWLS позволяет нескольким потокам получать доступ во время операций чтения и блокировать операцию записи. Таким образом, два потока могут считываться, т.е. Касаться коллекции одновременно.
Мое предложение состояло в том, чтобы изменить RWLS на простой lock() и попытаться воспроизвести переполнение стека.
Если это исправляет вашу проблему, я бы предложил подумать о переходе на 4.0, чтобы воспользоваться параллельными коллекциями. В качестве альтернативы вам может понадобиться создать собственный поточно-кавитный калорийный кашель для кашля, чтобы вы могли лучше контролировать эту ситуацию.
http://msdn.microsoft.com/en-us/library/xfhwa508.aspx
Безопасность потоков
Открытый статический (общий в Visual Basic) члены этого типа являются потокобезопасными. Любые члены экземпляра не гарантируют безопасность потоков.
Словарь < (Of < (TKey, TValue > ) > ) может поддерживать несколько считывателей одновременно, пока коллекция не модифицировано. Несмотря на это, перечисление через коллекцию по существу не является потокобезопасным процедура. В редком случае, когда перечисление связано с записью доступа, коллекция должна быть заблокирован в течение всего перечисление.. Чтобы обеспечить сбор для доступа к нескольким потокам для чтение и письмо, вы должны выполнить собственную синхронизацию.
Акцент на мой.
ChangeLogProcess
- особенно установщикStatus