【发布时间】:2019-04-16 01:46:29
【问题描述】:
我使用的是 Delphi 版本(Delphi 10.2u2)
我的目标是使用 Web 服务来处理通过 Indy 框架的多线程 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...) 错误等...
经过一番搜索,我发现错误是由于在运行子线程之前释放了所需的库。
确实,由于SSL/Winsock(尤其是)库在未完成的HTTP请求期间被释放,请求的连续性会调用一些不可用的函数并导致空指针异常、访问冲突等......
在使用 TTasks 之前,我使用的是常规 TThread,一切正常,因为在应用程序销毁事件中,我一直等到我的所有 TThread 完成他们的任务,然后才让销毁过程走得更远。
据我所知,我可能错了,Delphi 管理这部分,但似乎是在单元完成后才做的。
对我来说最好的解决方案是能够在我的程序的破坏事件中控制我的 TTasks 的状态,比如。等到我所有的 TTask 完成他们的任务。
但是,当我找不到一种方法来做到这一点而不引发其他类型的异常时,例如“操作已取消”
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 用于我最大的项目之一,我无法部署带有此类错误消息的应用程序 ^_^
亲切的问候,
【问题讨论】:
-
"等到我所有的 TTasks 完成他们的任务" - 看看
TTask.WaitForAll()。TTask实现了ITask接口。创建一个正在运行的ITask对象数组,然后您可以在该数组上WaitForAll()退出应用程序