与Delphi 2007的AsyncCall

Iva*_*ark 11 delphi multithreading asynchronous delphi-2007

我基本上想要的是启动AsyncCall并继续我的代码加载.我有接口部分,消耗大量的时间(600 + ms),我想在独立的线程中加载此代码.

我试图用AsyncCall这样的东西:

procedure Load;
begin
...
end;

initialization
  AsyncCall(@Load, []); // or LocalAsyncCall(@Load)
Run Code Online (Sandbox Code Playgroud)

但是,此Load过程实际上是在主线程中启动,而不是在新创建的线程中启动.如何强制将Load程序加载到除以外的任何线程中MainThread

我可以创建TThreadExecute这个,但我想强制AsyncCallLocalAsyncCall或任何从AsyncCall库中进行工作.

谢谢你的帮助.

kob*_*bik 8

你尝试过这样的事吗?:

procedure Load;
begin
  if GetCurrentThreadId <> MainThreadID then
    Beep;
end;

var a: IAsyncCall;

initialization
  a := AsyncCall(@Load, []);
  a.ForceDifferentThread;
Run Code Online (Sandbox Code Playgroud)

ForceDifferentThread()告诉AsyncCalls,不能在当前线程中执行分配的函数.


Dav*_*nan 5

问题是您的代码没有保留函数IAsyncCall返回的接口AsyncCall.

AsyncCall(@Load, []);
//AsyncCall returns an IAsyncCall interface,
//but this code does not take a reference to it
Run Code Online (Sandbox Code Playgroud)

因此,一旦初始化部分完成,返回的接口的引用计数就会减少到零.因此,这释放了实现此接口的对象:

destructor TAsyncCall.Destroy;
begin
  if FCall <> nil then
  begin
    try
-->   FCall.Sync; // throw raised exceptions here
    finally
      FCall.Free;
    end;
  end;
  inherited Destroy;
end;
Run Code Online (Sandbox Code Playgroud)

关键行是Sync强制异步调用执行完成的调用.所有这些都发生在主线程中,它解释了您报告的行为.


解决方案是您只需将IAsyncCall接口存储在变量中即可使接口保持活动状态.

var
  a: IAsyncCall;

initialization
  a := AsyncCall(@Load, []);
Run Code Online (Sandbox Code Playgroud)

在实际代码中,您需要确保Load在运行任何依赖的代码之前已完成Load.当你的程序的地步了需要它Load已被称为它调用Sync的上IAsyncCall界面.

所以你可能会写这样的东西.

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.
Run Code Online (Sandbox Code Playgroud)

EnsureLoaded来自其他需要Load运行的单位的电话.或者,也可以EnsureLoadedMyUnit依赖于Load运行的任何方法调用.后一种选择有更好的封装.

  • @David你的答案是对的.如果接口范围消失,他将需要全局IAsyncCall接口不立即同步.在不存储接口的情况下永远不要调用AsyncCalls函数是非常重要的.最坏的情况是编译器必须生成1个临时接口变量的循环.循环将按顺序执行调用,因为每次迭代只有1个接口被重新分配. (2认同)