Использование System.threading, как проверить и завершить уже запущенную ITask в случае выполнения в течение определенного периода времени

#multithreading #delphi #delphi-xe #indy #idhttp

#многопоточность #delphi #delphi-xe #indy #idhttp

Вопрос:

Я новичок в Multithreading , у меня есть процедура, которая выполняет серию операций с использованием indy (вход на сайт и загрузка файлов и …), иногда, когда сайт не реагирует или это занимает слишком много времени, исключения не возникает даже при заданном значении idHttp.connectTimeout и idHttp.readTimeout , или иногда это происходит, но не в указанное мной время !!, вот почему я предпочитаю проверить задачу и посмотреть, выполняется ли, например, ITask в течение 30 сек, это должно быть прекращено!, я пытался использовать itask.cancel , но это отменяет только в том случае, если что-то находится в очереди и не завершает задачу, которая уже запущена, каково решение моей проблемы?

просто чтобы вы знали, что происходит в моей программе :

изначально моя программа создает классы на основе списка профилей и запускает процесс входа в систему и загрузки, я хочу завершить любой startDownloadProcess , который занимает более 30 секунд
вот пример кода :

 // this is what i used to do
for I := 0 to mProfileList.count - 1 do
begin
  myClass := TMyClass.create(mProfileList[i]);
  //sometimes this takes a very very long time and i don't want that.
  myClass.startDownloadProcess;
end;

// here is what i have in mind 
for I := 0 to mProfileList.count - 1 do
begin
  mITaskArray[i] := TTask.run(procedure
    begin
     myClass := TMyClass.create(mProfileList[i]);
     myClass.startDownloadProcess;
    end);
end;
  

Что мне нужно :
я хочу, чтобы каждая задача зависела от предыдущей (очереди) и ждала, пока предыдущая не завершится, и если задача занимает более 30 секунд, она завершается, и очередь продолжается.

теперь я знаю, что в этом коде может быть много чего неправильного, но именно поэтому я здесь, я немного не понимаю, как действовать дальше и правильно ли то, что я делаю вообще!

Комментарии:

1. Вы должны регулярно проверять внутри задачи, отменяется ли она: if TTask.CurrentTask.Status = TTaskStatus.Canceled then exit;

2. @LURD но разве задача не выполняется только один раз?, если да, то как я могу проверить статус, если он застрял в строке (например, IdHTTP.get());

3. Вы не можете завершать задачи и потоки извне. Вам нужно, чтобы они сотрудничали. Вы можете завершать процессы.

4. Именно то, что уже было предложено

5. @LURD TTask , не TIdHTTP выполняется в своем собственном потоке. TIdHTTP выполняет свою работу в любом вызываемом потоке Get / Post . Но это не имеет значения, поскольку OnWork события запускаются только при активном обмене байтами, поэтому, если сайт не отвечает, тогда нет активности сокета для запуска событий. Вы должны использовать тайм-ауты сокета. Обязательно используйте ConnectTimeout и ReadTimeout (в Indy их нет SendTimeout , но у базового сокета есть своя SO_SNDTIMEO опция на уровне API), а также рассмотрите возможность включения TCP keepalives.

Ответ №1:

вы говорите, что вы новичок в многопоточности, поэтому помните, что никогда (never) не используйте TTASK / ITask или аналогичный TParalel. это полностью глючит! используйте вместо TAnonymousThread

   MyThread := TThread.createAnonymousThread(
    Procedure
    Begin
       repeat
         if MyThread.checkterminated then exit;
         if moreThan30secondsRunning then exit;
         ....
       until wordDone;
    end).start;