我知道很多线程都讨论过Delphi线程。我试过检查它们,但没有找到我的问题的答案。
背景 我发现在浏览器加载Adobe Acrobat Reader DC后,释放TWebBrowser可能需要10秒以上。我想不知何故它正在检查更新或其他什么。尝试使用浏览器关闭表单时很烦人。
我想也许我可以让后台线程释放浏览器。所以我将浏览器变量移动到一个全局变量(私有存储在单元的实现部分)。一次只能使用其中一种形式。然后我尝试让一个线程在后台释放它。它没有像我预期的那样工作。
示例代码
interface
TMyform = class(TForm)
pnlBowserHolder: TPanel;
procedure FormDestroy(Sender: TObject);
procedure FormCreate(Sender: TObject);
private
//WebBrowser : TWebBrowser; <-- moved to global variable
public
{ Public declarations }
end;
implementation
type
TBackgroundBrowserKillerThread = class(TThread)
public
procedure Execute; override;
end;
var
WebBrowser : TWebBrowser;
BrowserKillerThread : TBackgroundBrowserKillerThread;
procedure TfrmLabImageViewer.FormCreate(Sender: TObject);
begin
WebBrowser := TWebBrowser.Create(Self);
TWinControl(WebBrowser).Parent := pnlBowserHolder;
WebBrowser.Align := alClient;
end;
procedure TfrmLabImageViewer.FormDestroy(Sender: TObject);
begin
BrowserKillerThread := TBackgroundBrowserKillerThread.Create(true);
Application.ProcessMessages;
BrowserKillerThread.Execute();
//WebBrowser.Free;
end;
procedure TBackgroundBrowserKillerThread.Execute();
begin
TWinControl(WebBrowser).Parent := nil;
FreeAndNil(WebBrowser);
self.FreeOnTerminate := true;
BrowserKillerThread := nil; //free reference to thread, shouldn't affect ability of self to free itself (?)
end;
问题:
提前非常感谢。
KT
答案 0 :(得分:8)
我的理解是错误的.execute是什么?
是。这不是你如何做线程。通常,您首先必须决定在最初启动它之后是否需要对该线程执行任何操作。如果是这样,请保留引用,不要使用FreeOnTerminate
,并在终止后自行处理线程的破坏。如果不这样做,请不要保留参考,设置FreeOnTerminate
,然后将其发送。
您既不会在线程的执行中设置FreeOnTerminate
,也不会对具有此设置的线程保持全局引用。您也不是通过调用它的Execute
方法来启动线程,而是通过创建非挂起或调用Start
来创建线程。只是调用Execute
实际上并没有启动线程,而是在当前线程的上下文中执行此过程,这就是为什么它仍然需要10秒。
你的例子将成为:
procedure TfrmLabImageViewer.FormDestroy(Sender: TObject);
var BrowserKillerThread: TBackgroundBrowserKillerThread;
begin
BrowserKillerThread := TBackgroundBrowserKillerThread.Create(true);
BrowserKillerThread.FreeOnTerminate := true;
BrowserKillerThread.Start;
end;
procedure TBackgroundBrowserKillerThread.Execute();
begin
TWinControl(WebBrowser).Parent := nil; // I don't think you need to nil the parent here, but probably does no harm
FreeAndNil(WebBrowser);
end;
现在线程是正确的,但逻辑仍然是错误的。正如您已经注意到的那样,您不能从主线程以外的线程修改VCL对象,这包括Free
。你必须用Synchronize
来做这件事,这会破坏线程化的目的。
我也认为在线程中杀死浏览器的想法,因为否则花费太长时间只是在与症状作斗争,而不是与原因作斗争。我认为最好先找出为什么这么长时间,并解决这个问题,而不是试图以这种方式绕过这个问题。但这超出了本问题的范围,如果您遇到问题,则应针对此特定问题提出单独的问题。