multithreading - 这个Delphi Thread代码正确吗?

标签 multithreading delphi acrobat twebbrowser

我知道在许多线程上都讨论过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;

问题:
  • 当我在 Debug模式下单步执行FormDestroy代码时,包含BrowserKillerThread.Execute();的行。仍然需要10秒才能执行。我以为这会启动另一个线程并立即返回。但事实并非如此。我的理解对.execute做什么有误?还是发生了有趣的事情?
  • 我在做坏事吗?我已经读过VCL不是线程安全的,并且一个人不能/不应该从另一个线程访问VCL对象。我希望这在这种情况下不适用,因为我只是在释放对象而没有计划进一步的交互。
  • 如果终止时线程自身释放,我认为这会使我的BrowserKillerThread指针悬空。那么可以像我一样给nil赋值吗?
  • 关于如何更好地做到这一点的任何建议?

  • 提前非常感谢。

    韩国电信

    最佳答案

    Is my understanding wrong of what .execute does??



    是的。这不是您执行线程处理的方式。通常,首先必须确定在最初启动线程后是否需要对该线程执行任何操作。如果是这样,请保留引用,不要使用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做到这一点,这会破坏线程化的目的。

    我还认为杀死线程中的浏览器的想法是因为它要花费很长的时间,而只是消除症状,而不是原因。我认为最好首先找出为什么要花这么长时间并加以解决,而不是试图以这种方式规避问题。但这不在此问题的范围内,如果您对此有疑问,则应针对此特定问题询问另一个问题。

    关于multithreading - 这个Delphi Thread代码正确吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42126528/

    相关文章:

    pdf - 用于查看 PDF 坐标的免费工具

    java - 创建一个工作线程并从 servlet 或 Spring Controller 运行

    excel - 应用程序结束后保持 Excel 打开(Delphi 自动化)

    windows - 杂技 Actor (阅读器): to open at a specific page number via command line on Windows

    javascript - VBA填充多行PDF?

    windows - 使用 DrawText 或类似函数渲染下标

    multithreading - 线程上下文切换 Vs.进程上下文切换

    Python - 池不使用所有内核

    java - 如何降低时间复杂度

    delphi - Delphi中截取串口数据