我正在使用Delphi版本(Delphi 10.2u2)
我的目标是通过Indy框架使用Web服务来处理多线程GET,POST命令,没有什么真正复杂的,并且一切正常,直到在请求期间关闭应用程序为止。
为此,我使用TidHTTPClient处理命令,并使用TIdSSLIOHandlerSocketOpenSSL支持流量加密。
对于多线程,我正在使用并行编程库(PPL)中的TTask。 “在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 ...)错误等...
经过一番搜索,我发现该错误是由以下事实造成的:所需的库在运行的子线程之前被释放。
实际上,因为未完成的HTTP请求期间释放了SSL / Winsock(尤其是)库,所以请求的连续性将调用某些不可用的函数,并导致空指针异常,访问冲突等...
在使用TTasks之前,我使用的是常规TThread,并且一切都很好,因为在应用程序destroy事件上,我一直等到所有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,我无法部署带有此类错误消息的应用程序^ _ ^
问候,
答案 0 :(得分:0)
谢谢您让我走上雷米(Remy)的路。这是问题的完整解决方案。
procedure TForm3.FormDestroy(Sender: TObject);
begin
while not TTask.WaitForAll(FTasks, 1000) do
CheckSynchronize();
end;