Delphi 2007 中的 AsyncCall

发布于 2024-12-25 18:13:19 字数 588 浏览 1 评论 0原文

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

我尝试使用 AsyncCall 来做这样的事情:

procedure Load;
begin
...
end;

initialization
  AsyncCall(@Load, []); // or LocalAsyncCall(@Load)

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

我可以创建 TThread 并执行此操作,但我想强制 AsyncCall 或 LocalAsyncCall 或 AsyncCall 中的任何内容 库才能工作。

感谢您的帮助。

What I basically want is to start AsyncCall and proceed with my code loading. I have Interface section that consumes lots of time (600+ms) and I want to load this code in independent thread.

I've tried to use AsyncCall to make something like this:

procedure Load;
begin
...
end;

initialization
  AsyncCall(@Load, []); // or LocalAsyncCall(@Load)

However, this Load procedure actually starts in Main thread and not in the new created thread. How can I force the Load procedure to be loaded in any thread other than MainThread?

I can create TThread and Execute this but I want to force AsyncCall or LocalAsyncCall or anything from AsyncCall library to make to work.

Thanks for your help.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

云醉月微眠 2025-01-01 18:13:19

你尝试过这样的事情吗?:

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

var a: IAsyncCall;

initialization
  a := AsyncCall(@Load, []);
  a.ForceDifferentThread;

ForceDifferentThread() 告诉 AsyncCalls 分配的函数必须
不在当前线程中执行。

Have you tried something like this?:

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

var a: IAsyncCall;

initialization
  a := AsyncCall(@Load, []);
  a.ForceDifferentThread;

ForceDifferentThread() tells AsyncCalls that the assigned function must
not be executed in the current thread.

待天淡蓝洁白时 2025-01-01 18:13:19

问题是您的代码没有保留由 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。后一种选择具有更好的封装性。

The problem is that your code is not retaining the IAsyncCall interface that is returned by the AsyncCall function.

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

Because of this, the interface that is returned has its reference count decremented to zero as soon as the initialization section completes. This therefore frees the object that implements the interface which does this:

destructor TAsyncCall.Destroy;
begin
  if FCall <> nil then
  begin
    try
-->   FCall.Sync; // throw raised exceptions here
    finally
      FCall.Free;
    end;
  end;
  inherited Destroy;
end;

The key line is the call to Sync which forces the asynchronous call to be executed to completion. All this happens in the main thread which explains the behaviour that you report.


The solution is that you simply need to keep the IAsyncCall interface alive by storing it in a variable.

var
  a: IAsyncCall;

initialization
  a := AsyncCall(@Load, []);

In the real code you need to ensure that Load had completed before running any code that is reliant on Load. When your program reached a point where it required Load to have been called it has to call Sync on the IAsyncCall interface.

So you might write it something like this.

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.

The call EnsureLoaded from other units that required Load to have run. Or, alternatively, call EnsureLoaded from any methods exported by MyUnit that depended on Load having run. The latter option has much better encapsulation.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文