您可以编写一些严重的 hacky、难以形容的糟糕代码,以使您能够安全地调用 TThread 的 Execute()。但这是一件荒谬的事情。 TThread 类的重点在于:
- 在操作系统中启动一个新线程;
- 然后在该线程上调用
Execute()。
所以:
- 如果您不需要线程,则绝对没有意义启动您不想使用的线程。
- 您需要阻止
Execute() 对其线程运行进行任何处理。
- 然后您可以从主线程调用
Execute。
- 但由于您无法保证线程在调用
Execute() 时不进行任何处理需要多长时间,所以您仍然需要等待在销毁TThread 对象之前完成线程。
GUI 数学过程与在线程中调用的过程有点不同,所以我不能简单地提取方法并调用它。
这完全没有意义。
如果您的两个“数学程序”不同,那么尝试从 GUI 调用 thread-implementation 会改变程序的行为。相反,如果你可以重用线程实现,那么你肯定也可以 提取方法! (或者至少是共同的元素。)
注意
也就是说,在共享可能在 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;
要从子线程运行,一个简单的线程包装器就足够了。然后你可以在主线程中创建 runnable 对象,并将其传递给线程包装器。
{ 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;
免责声明
我没有测试过这段代码,因为我认为做这样的事情没有任何好处。通过强制代码在主线程上运行,用户一无所获。此外,同步代码的范例与异步代码根本不同。尝试实现混合会降低可维护性,因为您的“业务代码”与技术细节混杂在一起。
使用风险自负。