Indy SSL 组件终结(PPL / TTask)引起的访问冲突
Access Violation caused by Indy SSL component finalization (PPL / TTask)
我正在使用 Delphi 版本 (Delphi 10.2u2)
我的目标是使用 Web 服务来处理多线程 GET,通过 Indy 框架 POST 命令,没有什么真正复杂的,一切正常,直到我在请求期间关闭应用程序。
为此,我使用 TidHTTPClient 来处理命令并使用 TIdSSLIOHandlerSocketOpenSSL 来支持流量加密。
对于多线程,我使用并行编程库 (PPL) 中的 TTask。 "I'm quite new in using this library with 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,并且一切正常,因为在应用程序销毁事件上,我一直在等待,直到我的所有 TThread 完成它们的任务,然后才让销毁过程走得更远。
据我所知,我可能是错的,Delphi管理那部分,但似乎是在单位最终确定后才进行。
对我来说最好的解决方案是能够控制我的 TTasks 在我的程序的破坏事件上的状态。等到我所有的 TTasks 完成他们的任务。
但是,当我找不到不引发其他类型异常(如 "Operation Canceled"
的方法时
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 用于我最大的项目之一,我无法部署带有此类错误消息的应用程序 ^_^
亲切的问候,
谢谢你让我踏上雷米之路。这是问题的完整解决方案。
procedure TForm3.FormDestroy(Sender: TObject);
begin
while not TTask.WaitForAll(FTasks, 1000) do
CheckSynchronize();
end;
我正在使用 Delphi 版本 (Delphi 10.2u2)
我的目标是使用 Web 服务来处理多线程 GET,通过 Indy 框架 POST 命令,没有什么真正复杂的,一切正常,直到我在请求期间关闭应用程序。
为此,我使用 TidHTTPClient 来处理命令并使用 TIdSSLIOHandlerSocketOpenSSL 来支持流量加密。
对于多线程,我使用并行编程库 (PPL) 中的 TTask。 "I'm quite new in using this library with 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,并且一切正常,因为在应用程序销毁事件上,我一直在等待,直到我的所有 TThread 完成它们的任务,然后才让销毁过程走得更远。
据我所知,我可能是错的,Delphi管理那部分,但似乎是在单位最终确定后才进行。
对我来说最好的解决方案是能够控制我的 TTasks 在我的程序的破坏事件上的状态。等到我所有的 TTasks 完成他们的任务。
但是,当我找不到不引发其他类型异常(如 "Operation Canceled"
的方法时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 用于我最大的项目之一,我无法部署带有此类错误消息的应用程序 ^_^
亲切的问候,
谢谢你让我踏上雷米之路。这是问题的完整解决方案。
procedure TForm3.FormDestroy(Sender: TObject);
begin
while not TTask.WaitForAll(FTasks, 1000) do
CheckSynchronize();
end;