簡體   English   中英

如何在 GUI 線程中調用 Thread.Execute?

[英]How Do I Call a Thread.Execute in GUI Thread?

有一個TThread后代類,它有自己的Execute方法做一些數學運算。 它工作正常,但我正在尋找以下類型的優化。 程序的 GUI 線程和上下文確定要創建、運行和釋放的這些線程的必要實例的數量。 在某些(罕見的或用戶確定的)情況下,創建一個實例就足夠了。

目前我使用以下結構(偽代碼):

if ThreadsCount>1 then
  begin
    Creation of threads
    starting them
    waiting for results
    evaluating and assigning the best result
    freeing the threads
  end
else
  starting the math procedure (edited here separately)

// and in MyThread class declaration
procedure Execute... (edited here separately)

所以代碼中有兩個地方有我的數學程序,如果應用了一些數學更改,我必須編輯它們。 GUI 數學過程與在線程中調用的過程略有不同,因此我不能簡單地提取該方法並調用它。

我想知道有沒有辦法在GUI線程中創建一個線程實例並調用它的Execute方法?

您可以編寫一些非常hacky、難以形容的糟糕代碼,以使您能夠安全地調用TThreadExecute() 但這是一件很荒謬的事情。 TThread類的重點在於:

  • 在操作系統中啟動一個新線程;
  • 然后在該線程上調用Execute()

所以:

  1. 如果您不需要線程,那么啟動您不想使用的線程絕對沒有意義
  2. 您需要阻止Execute()對其thread-run進行任何處理。
  3. 然后,您可以從主線程調用Execute
  4. 但是由於您無法保證線程在調用Execute()進行任何處理需要多長時間,因此您仍然需要等待線程完成才能銷毀TThread對象。

GUI 數學過程與在線程中調用的過程略有不同,因此我不能簡單地提取該方法並調用它。

這完全沒有意義。

如果您的兩個“數學程序”不同,那么嘗試從 GUI 調用線程實現將改變您程序的行為。 相反,如果您可以重用線程實現,那么您當然也可以提取方法 (或者至少是共同元素。)


警告

也就是說,共享可能在TThread.Execute()運行的代碼時需要謹慎。 任何必須在主線程上運行的代碼都需要同步或排隊。 TThread對象中,您只需調用Synchronize()Queue()方法。 但是,共享代碼不應該位於TThread對象上,這會使事情變得有點棘手。

要解決此問題,您可以在TThread上使用Synchronize()Queue()類方法。 這允許您在不實例化TThread實例的情況下進行同步。 (請注意,從主線程調用這些方法是安全的,因為在這種情況下它們將直接調用同步方法。)

下面幾行的代碼應該可以解決問題。

在合適的對象中實現您的共享代碼。 這在概念上是一個可運行的對象,您可能想研究一下。

TSharedProcess = class
private
  { Set this if the process is run from a child thread,
    leave nil if run from main thread. }
  FThread: TThread;
  procedure SyncProc();
public
  procedure Run();
  property Thread: TThread read FThread write FThread;
end;

procedure TSharedProcess.Run();
begin
  ...
  TThread.Synchronize(FThread, SyncProc);
  ...
end;

當您想從主線程運行共享代碼時,以下是一個選項。

begin
  LProc := TSharedProcess.Create(...);
  try
    LProc.Run();
  finally
    LProc.Free;
  end;
end;

要從子線程運行,一個簡單的線程包裝器就足夠了。 然后你可以在主線程中創建可運行對象,並將其傳遞給線程包裝器。

{ TShardProcessThread for use when calling from child thread. }

constructor TSharedProcessThread.Create(AProc: TSharedProcessThread);
begin
  FProc := AProc;
  FProc.Thread := Self;
  inherited;
end;

procedure TShardProcessThread.Execute();
begin
  FProc.Run();
end;

{ Main thread creates child thread }
begin
  { Keep reference to FProc because it can only be destroyed after
    thread terminates. 
    TIP: Safest would be to use a reference counted interface. }
  FProc := TSharedProcess.Create(...);
  try
    LThread := TShardProcessThread.Create(FProc);
    LThread.OnTerminate := HandleThreadTerminate;
  except
    { Exception in thread create means thread will not run and
     will not terminate; so free object immediately. }
    FProc.Free;
    raise;
  end;
end;

免責聲明

我沒有測試過這段代碼,因為我認為做這樣的事情沒有任何好處。 通過強制代碼在主線程上運行,用戶一無所獲。 此外,同步代碼的范式與異步代碼有着根本的不同。 嘗試實現混合會降低可維護性,因為將您的“業務代碼”與技術細節混雜在一起。

使用風險自負。

解決這個問題的方法是將您需要在工作線程或主線程中執行的代碼提取到一個方法中。 然后,您可以從工作線程的Execute方法或主線程代碼中調用該代碼。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM