Я использую версию Delphi (Delphi 10.2u2)
Моя цель - поиграть с веб-сервисом для обработки многопоточных команд GET и POST через платформу Indy, ничего сложного, и все работает нормально, пока я не закрою приложение во время запроса.
Для этого я использую TidHTTPClient для обработки команд и TIdSSLIOHandlerSocketOpenSSL для поддержки шифрования трафика.
Для многопоточности я использую TTask из библиотеки параллельного программирования (PPL). «Я новичок в использовании этой библиотеки с Delphi».
Вот пример кода:
procedure TForm3.Button1Click(Sender: TObject);
begin
TTask.Create(
procedure
var HTTP : TidHTTP;
SSL : TIdSSLIOHandlerSocketOpenSSL;
content : String;
begin
HTTP := TIdHTTP.Create(nil);
SSL := TIdSSLIOHandlerSocketOpenSSL.create(nil);
SSL.SSLOptions.Method := sslvSSLv23;
HTTP.IOHandler := SSL;
HTTP.ConnectTimeout := 20000;
HTTP.ReadTimeout := 60000;
HTTP.HandleRedirects := true;
try
{
If we close the application during the Get, it raise an exception.
This is because the SSL Library is freed before the get has the time to stop
finalization
UnLoadOpenSSLLibrary(); // called before get is over
}
Content := HTTP.Get('https://www.google.com/');
TThread.Synchronize(nil, procedure begin
memo1.text := Content;
end);
except
// ...
on E : Exception do
TThread.Synchronize(nil, procedure begin
memo1.Text := 'Error';
end);
end;
SSL.Free;
HTTP.Free;
end).Start();
end;
Если вы скомпилируете и выполните этот код, вы увидите, что все работает нормально, пока не решите закрыть программу во время запроса (GET, POST или что-то еще).
Ошибка может варьироваться в зависимости от точного момента, когда вы закрываете приложение во время HTTP-запроса. Это будет нарушение прав доступа, ошибка Winsock2 (WSA ...) и т. Д.
После небольшого поиска я обнаружил, что ошибка была вызвана тем, что необходимые библиотеки освобождаются до запуска подпотоков.
Действительно, поскольку библиотеки SSL / Winsock (особенно) освобождаются во время незавершенного HTTP-запроса, непрерывность запроса вызовет некоторую недоступную функцию и вызовет исключение нулевого указателя, нарушение доступа и т. Д.
Перед использованием TTasks я использовал обычные TThread, и все работало нормально, потому что в событии уничтожения приложения я ждал, пока все мои TThread не завершат свою задачу, прежде чем позволить процессу уничтожения зайти дальше.
Насколько я знаю, и я, вероятно, ошибаюсь, Delphi управляет этой частью, но, похоже, делает это после завершения работы над модулями.
Лучшим решением для меня было бы иметь возможность контролировать состояние моих TTasks в случае разрушения моей программы, например. Подождите, пока все мои TTasks завершат свои задачи.
НО, когда я не могу найти способ сделать это, не вызывая исключения другого типа, например «Операция отменена»
procedure TForm3.FormDestroy(Sender: TObject);
begin
ATask.Cancel;
repeat
if ATask.Wait(500) = false then begin
CheckSynchronize();
end;
until (ATask = nil);
end;
Приведенный выше пример не сработает ...
Я уверен, что делаю что-то не так, я не мог найти никакой помощи, связанной с этой темой, в другом месте, Delphi PPL звучит много нового или моя проблема действительно особенная.
Заранее большое спасибо за вашу помощь.
Я действительно хочу использовать PPL для одного из моих самых больших проектов, я не могу развернуть приложение с такими сообщениями об ошибках ^ _ ^
С уважением,
TTask.WaitForAll()
.TTask
реализуетITask
интерфейс. Создайте массив из запущенныхITask
объектов, а затем вы можетеWaitForAll()
в этом массиве перед выходом из приложения. - person Remy Lebeau   schedule 13.11.2018