Я использую версию 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 управляет этой частью, но, похоже, делает это после завершения Units.
Лучшим решением для меня было бы управлять состоянием моих 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 для одного из моих самых больших проектов, я не могу развернуть приложение с такими сообщениями об ошибках ^ _ ^
С уважением,
Всего 1 ответ
Спасибо, что отправил меня на путь Реми. Вот полное решение проблемы.
procedure TForm3.FormDestroy(Sender: TObject);
begin
while not TTask.WaitForAll(FTasks, 1000) do
CheckSynchronize();
end;