Ошибка EAurgumentOutOfRange при работе с параллельными циклами в Delphi XE7
Вопрос пользователя связан с ошибкой EAurgumentOutOfRange, возникающей при попытке использования нового параллельного API в Delphi XE7 для выполнения ресурсоемкой операции. В примере кода, представленном пользователем, используется цикл TParallel.For для распараллеливания обработки данных. Однако, при попытке вызова обработчика события fOnCreateShapesProgress из этого цикла, возникает указанная ошибка.
Пример кода:
procedure TTerritoryList.SetUpdating(const Value: boolean);
var
i, n: Integer;
begin
if (fUpdating <> Value) or not Value then
begin
fUpdating := Value;
n := Count;
i := 0;
TParallel.For(0, Count - 1,
procedure(Index: Integer)
begin
Territory[Index].Updating := Value; // ресурсоемкая операция
TInterlocked.Increment(i);
TThread.Queue(TThread.CurrentThread,
procedure
begin
if assigned(fOnCreateShapesProgress) then
fOnCreateShapesProgress(nil, 'Reconfiguring ' + Territory[Index].Name, i / n);
end);
end);
end;
end;
Проблема:
При использовании TThread.Queue в параллельном цикле TParallel.For возникает ошибка EAurgumentOutOfRange, если в коде присутствует вызов обработчика события.
Решение:
Из комментариев к вопросу пользователя становится ясно, что проблема кроется в использовании TThread.Queue с параметром TThread.CurrentThread. Это некорректно, так как TThread.CurrentThread - это именно тот поток, из которого выполняется вызов TThread.Queue, и ожидается, что будет использован другой поток, например, главный поток приложения.
Чтобы решить проблему, следует использовать однопараметрический вариант TThread.Queue, который не принимает параметр потока, а также переместить инкремент счетчика прогресса в главный поток, чтобы избежать гонки данных:
procedure TTerritoryList.SetUpdating(const Value: boolean);
var
i, n: Integer;
begin
if (fUpdating <> Value) or not Value then
begin
fUpdating := Value;
n := Count;
TParallel.For(0, Count - 1,
procedure(Index: Integer)
begin
Territory[Index].Updating := Value; // ресурсоемкая операция
TThread.Queue(
procedure
begin
TInterlocked.Increment(i); // инкремент счетчика в главном потоке
if assigned(fOnCreateShapesProgress) then
fOnCreateShapesProgress(nil, 'Reconfiguring ' + Territory[Index].Name, i / n);
end);
end);
end;
end;
Также важно отметить, что в последних версиях Delphi для атомарного инкремента следует использовать метод AtomicIncrement.
Дополнительные замечания:
Перед использованием параллельных циклов рекомендуется обновить свой проект до последнего обновления Delphi XE7, так как в нем исправлены некоторые ошибки, связанные с параллельным API.
Использование TThread.Synchronize вместо TThread.Queue также может быть решением для выполнения кода в главном потоке, но важно убедиться, что это необходимо, так как TThread.Synchronize блокирует выполнение до завершения выполнения переданной ему процедуры.
Следуя этим рекомендациям, можно избежать ошибки EAurgumentOutOfRange и успешно использовать параллельные циклы в Delphi XE7 для улучшения производительности ресурсоемких операций.
Вопрос пользователя касается исправления ошибки EAurgumentOutOfRange, связанной с неправильным использованием TThread.Queue в контексте параллельного программирования в Delphi XE7.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.