Описание
При первом одновременном обращении из фоновых заданий к одному значению системного перечисления иногда возникает System.IndexOutOfRangeException.
В примере используется НаправлениеПоиска.СКонца.
Минимальный пример
Процедура ПрочитатьЗначениеПеречисления() Экспорт
Приостановить(100);
Значение = НаправлениеПоиска.СКонца;
КонецПроцедуры
КоличествоЗаданий = 1000;
Менеджер = Новый МенеджерФоновыхЗаданий;
Задания = Новый Массив;
Для НомерЗадания = 1 По КоличествоЗаданий Цикл
Задания.Добавить(
Менеджер.Выполнить(
ЭтотОбъект,
"ПрочитатьЗначениеПеречисления",
,
Истина
)
);
КонецЦикла;
Менеджер.ОжидатьВсе(Задания);
Для Каждого Задание Из Задания Цикл
Если Задание.ИнформацияОбОшибке <> Неопределено Тогда
Сообщить(Задание.ИнформацияОбОшибке.ПодробноеОписаниеОшибки());
Прервать;
КонецЕсли;
КонецЦикла;
Ожидаемое поведение
Все фоновые задания успешно получают значение НаправлениеПоиска.СКонца.
Фактическое поведение
System.IndexOutOfRangeException: Index was outside the bounds of the array.
at System.Collections.Generic.HashSet`1.AddIfNotPresent(T value, Int32& location)
at System.Collections.Generic.HashSet`1.Add(T item)
at ScriptEngine.Machine.Contexts.EnumerationContext.WarnDeprecation(Int32 propNum)
at ScriptEngine.Machine.Contexts.EnumerationContext.GetPropValueInternal(Int32 propNum)
at ScriptEngine.Machine.Contexts.EnumerationContext.GetPropValue(Int32 propNum)
Ошибка возникает на строке:
Значение = НаправлениеПоиска.СКонца;
Предполагаемая причина
В EnumerationContext используется общее поле:
private readonly HashSet<int> _checkedDeprecatedProps = new HashSet<int>();
Метод WarnDeprecation() сначала вызывает Contains(), а затем Add() без синхронизации:
private void WarnDeprecation(int propNum)
{
if (_checkedDeprecatedProps.Contains(propNum))
return;
if (GetPropertyInfo(propNum) is SystemPropertyInfo { IsDeprecated: true })
{
SystemLogger.Write(
$"Обращение к устаревшему свойству {GetPropertyInfo(propNum).Name}.");
}
_checkedDeprecatedProps.Add(propNum);
}
При одновременном первом чтении свойства несколько фоновых заданий изменяют один экземпляр HashSet<int>. HashSet<T> не поддерживает конкурентную запись, что приводит к сбою внутри AddIfNotPresent().
Исходный код:
https://github.com/EvilBeaver/OneScript/blob/v2.2.0/src/ScriptEngine/Machine/Contexts/EnumerationContext.cs
Окружение
- OneScript: 2.2.0
- ОС: Windows Server 2022 Standard, 64-разрядная
- версия ОС: 10.0.20348
- установленный .NET Host: 9.0.5, x64
Описание
При первом одновременном обращении из фоновых заданий к одному значению системного перечисления иногда возникает
System.IndexOutOfRangeException.В примере используется
НаправлениеПоиска.СКонца.Минимальный пример
Ожидаемое поведение
Все фоновые задания успешно получают значение
НаправлениеПоиска.СКонца.Фактическое поведение
Ошибка возникает на строке:
Предполагаемая причина
В
EnumerationContextиспользуется общее поле:Метод
WarnDeprecation()сначала вызываетContains(), а затемAdd()без синхронизации:При одновременном первом чтении свойства несколько фоновых заданий изменяют один экземпляр
HashSet<int>.HashSet<T>не поддерживает конкурентную запись, что приводит к сбою внутриAddIfNotPresent().Исходный код:
https://github.com/EvilBeaver/OneScript/blob/v2.2.0/src/ScriptEngine/Machine/Contexts/EnumerationContext.cs
Окружение