2017-02-09 48 views
1

我知道Delphi線程已經在很多線程上討論過了。我試着審查他們,但沒有找到我的問題的答案。這個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; 

問題:

  • 當我通過在調試模式下FormDestroy碼步驟,含有BrowserKillerThread.Execute線();需要10秒鐘才能執行。我以爲這會啓動另一個線程並立即返回。但事實並非如此。我對執行程序的理解錯誤嗎?還是有趣的事情呢?
  • 我在做什麼壞事?我已經讀過VCL不是線程安全的,並且不能/不應該從另一個線程訪問VCL對象。我希望這不適用於這種情況,因爲我只是在沒有進一步交互計劃的情況下釋放對象。
  • 如果一個線程在終止時爲空,我認爲這會讓我的BrowserKillerThread指針懸空。那麼,我可以像這樣分配nil嗎?
  • 有關如何做得更好的建議?

非常感謝。

KT

+3

這是永遠不會工作。除了主線程之外,您無法從任何地方訪問任何類型的VCL控件,也無法在一個線程中創建它並在另一個線程中銷燬它。你寫的代碼不會改變任何東西 - 瀏覽器仍然被擁有它的主線程破壞;你只是從你的線程調用該代碼(除非你通過Synchronize來完成,否則這是錯誤的)。 –

+4

另外...您可能想要再次查看所有這些線程。我敢打賭,你還沒有看到過一個例子有從外部調用的執行方法。爲什麼?因爲那麼execute方法中的代碼將在調用它的線程的上下文中運行。 –

+2

我不會因使用Acro Reader DC的TWebBrower + v.15.023而導致關閉應用程序的延遲。你能給一個例子的網址,引發你的延遲? – MartynA

回答

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,這將打敗線程的目的。

我也認爲在一個線程中殺死瀏覽器的想法是因爲否則它需要太長的時間纔會對症下藥,而不是原因。我認爲最好找出爲什麼首先需要這麼長時間,並解決這個問題,而不是試圖以這種方式繞過這個問題。但是這超出了這個問題的範圍,如果你有問題,你應該爲這個特定的問題提出一個單獨的問題。

+0

偉大和有益的評論。非常感謝! – kdtop

+0

我一直在玩這個。我正在使用Delphi 10.它看起來像BrowserKillthread.Start應改爲BrowserKillthread.Resume。在我的Delphi版本中沒有。再次感謝... – kdtop

+0

我決定遵循DNR的建議,尤其是MartynA表示,他沒有經歷關閉延遲,並追究其根本原因。我從Windows的「開始」菜單打開Acrobat閱讀器,然後進入編輯首選項。我關閉了每一個可以找到的與安全服務器等進行交談的設置,並且爲我正在加載我的.pdf文件的文件夾(僅查看本地文件)做出安全例外......當然, 10秒延遲不見了。我在這裏寫這個以防別人有同樣的問題。再次感謝大家的幫助。 – kdtop