[英]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、難以形容的糟糕代碼,以使您能夠安全地調用TThread
的Execute()
。 但這是一件很荒謬的事情。 TThread
類的重點在於:
Execute()
。所以:
Execute()
對其thread-run進行任何處理。Execute
。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.