我主要想要的是启动AsyncCall并继续加载代码。我有一个接口部分,它消耗了很多时间(600多毫秒),我想在独立的线程中加载这些代码。
我试着用AsyncCall
制作这样的东西:
procedure Load;
begin
...
end;
initialization
AsyncCall(@Load, []); // or LocalAsyncCall(@Load)
然而,这个Load
过程实际上是在主线程中启动的,而不是在新创建的线程中。如何强制在MainThread
以外的任何线程中加载Load
过程?
我可以创建TThread
和Execute
,但我想强制AsyncCall
或LocalAsyncCall
或AsyncCall
库中的任何东西工作。
谢谢你的帮助。
你试过这样的东西吗?:
procedure Load;
begin
if GetCurrentThreadId <> MainThreadID then
Beep;
end;
var a: IAsyncCall;
initialization
a := AsyncCall(@Load, []);
a.ForceDifferentThread;
ForceDifferentiThread()告诉AsyncCalls分配的函数必须不能在当前线程中执行。
问题是您的代码没有保留AsyncCall
函数返回的IAsyncCall
接口。
AsyncCall(@Load, []);
//AsyncCall returns an IAsyncCall interface,
//but this code does not take a reference to it
因此,一旦初始化部分完成,返回的接口的引用计数就会减少到零。因此,这释放了实现接口的对象:
destructor TAsyncCall.Destroy;
begin
if FCall <> nil then
begin
try
--> FCall.Sync; // throw raised exceptions here
finally
FCall.Free;
end;
end;
inherited Destroy;
end;
关键行是对Sync
的调用,它强制执行异步调用直至完成。所有这些都发生在解释您报告的行为的主线程中。
解决方案是,只需将IAsyncCall
接口存储在一个变量中,即可使其保持活动状态。
var
a: IAsyncCall;
initialization
a := AsyncCall(@Load, []);
在实际代码中,在运行任何依赖于Load
的代码之前,您需要确保Load
已经完成。当程序达到需要调用Load
的程度时,必须在IAsyncCall
接口上调用Sync
。
所以你可以这样写。
unit MyUnit;
interface
procedure EnsureLoaded;
implementation
uses
AsyncCalls;
....
procedure Load;
begin
....
end;
var
LoadAsyncCall: IAsyncCall;
procedure EnsureLoaded;
begin
LoadAsyncCall := nil;//this will effect a call to Sync
end;
initialization
LoadAsyncCall := AsyncCall(@Load, []);
end.
来自其他需要Load
运行的单元的呼叫EnsureLoaded
。或者,也可以从MyUnit
导出的任何依赖于已运行的Load
的方法中调用EnsureLoaded
。后一种选择有更好的封装。