Обработка Ошибок при Использовании TTask.WaitForAny в Delphi: Получение Индекса Завершившейся с Ошибкой Задачи
При работе с многозадачностью в Delphi часто возникают ситуации, когда необходимо обрабатывать ошибки, возникающие в фоновых задачах. Одним из таких примеров является использование метода TTask.WaitForAny для ожидания завершения одной из задач в группе. В случае, если задача завершается с ошибкой, стандартный подход не позволяет получить индекс этой задачи, так как метод TTask.WaitForAny выбрасывает исключение, и переменная, в которую должен быть записан индекс, не инициализируется.
Давайте рассмотрим пример, который демонстрирует эту проблему:
t1 := TTask.Run(
procedure
begin
sleep(Random(1000) + 100);
raise Exception.Create('Error Message 1');
end
);
t2 := TTask.Run(
procedure
begin
sleep(Random(1000) + 100);
raise Exception.Create('Error Message 2');
end
);
res := -1;
try
res := TTask.WaitForAny([t1, t2]);
except
end;
Write('Index: ' + IntToStr(res)); // Выведет "-1"
ReadLn;
В данном случае, если одна из задач завершается с ошибкой, переменная res не будет содержать индекс этой задачи, а останется равной -1, которая была присвоена ей ранее.
Подтвержденный ответ
Для решения этой проблемы можно использовать следующий подход:
Создать собственный класс исключения, который будет содержать индекс задачи.
При возникновении ошибки в задаче, создать и поднять исключение с указанием индекса.
В обработчике исключений, анализировать агрегированное исключение на предмет наличия созданных собственных исключений.
Пример кода на Object Pascal (Delphi):
{$APPTYPE CONSOLE}
uses
System.SysUtils, System.Threading;
type
ETaskException = class(Exception)
private
FTaskIndex: Integer;
public
constructor Create(const Msg: string; const TaskIndex: Integer);
property TaskIndex: Integer read FTaskIndex;
end;
constructor ETaskException.Create(const Msg: string; const TaskIndex: Integer);
begin
inherited Create(Msg);
FTaskIndex := TaskIndex;
end;
var
t1, t2: ITask;
i, res: Integer;
begin
t1 := TTask.Run(
procedure
begin
sleep(150);
raise ETaskException.Create('Task failed', 0);
end
);
t2 := TTask.Run(
procedure
begin
sleep(100);
raise ETaskException.Create('Task failed', 1);
end
);
try
res := TTask.WaitForAny([t1, t2]);
Writeln('Task succeeded, index ' + IntToStr(res));
except
on E: EAggregateException do begin
for i := 0 to E.Count - 1 do begin
if (E.InnerExceptions[i] is ETaskException) then
WriteLn('Task failed, index ' + IntToStr((E.InnerExceptions[i] as ETaskException).TaskIndex));
end;
end;
end;
ReadLn;
end.
В данном коде, если одна из задач завершается с ошибкой, исключение EAggregateException содержит список внутренних исключений, среди которых можно найти созданное пользовательское исключение ETaskException и извлечь из него индекс задачи.
Альтернативный ответ
В качестве альтернативы, можно использовать цикл для проверки статуса каждой задачи в группе, и в случае, если задача завершилась с ошибкой, получить её индекс. Это позволяет избежать обработки исключений и может быть более эффективным в некоторых ситуациях.
var
tasks: TArray<ITask>;
i, finishedIndex: Integer;
begin
SetLength(tasks, 2);
tasks[0] := TTask.Run(...);
tasks[1] := TTask.Run(...);
finishedIndex := -1;
while finishedIndex = -1 do
begin
for i := Low(tasks) to High(tasks) do
begin
if tasks[i].Status = TTaskStatus.TS_Completed then
begin
finishedIndex := i;
if tasks[i].HasException then
begin
// Обработка ошибки для задачи с индексом i
end;
end;
end;
TTask.Yield;
end;
// Продолжение обработки результатов...
end;
Этот подход позволяет более гибко управлять процессом ожидания и обработкой результатов выполнения задач.
Описание контекста: При работе с многозадачностью в Delphi, при использовании метода `TTask.WaitForAny` для ожидания завершения одной из задач в группе, возникает проблема получения индекса задачи, завершившейся с ошибкой.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.