AsyncCall with Delphi 2007



我主要想要的是启动AsyncCall并继续加载代码。我有一个接口部分,它消耗了很多时间(600多毫秒),我想在独立的线程中加载这些代码。

我试着用AsyncCall制作这样的东西:

procedure Load;
begin
...
end;
initialization
  AsyncCall(@Load, []); // or LocalAsyncCall(@Load)

然而,这个Load过程实际上是在主线程中启动的,而不是在新创建的线程中。如何强制在MainThread以外的任何线程中加载Load过程?

我可以创建TThreadExecute,但我想强制AsyncCallLocalAsyncCallAsyncCall库中的任何东西工作。

谢谢你的帮助。

你试过这样的东西吗?:

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。后一种选择有更好的封装。

最新更新