AsyncCall与Delphi 2007 [英] AsyncCall with Delphi 2007

查看:185
本文介绍了AsyncCall与Delphi 2007的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



我试图使用 AsyncCall 可以这样做:

  procedure Load; 
begin
...
end;

初始化
AsyncCall(@Load,[]); //或LocalAsyncCall(@Load)

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



我可以创建 TThread 执行这个,但我想强制 AsyncCall LocalAsyncCall 或任何来自 AsyncCall 库的工作。



感谢您的帮助。

解决方案

问题是,代码不保留 AsyncCall 函数返回的 IAsyncCall 接口。

  AsyncCall(@Load,[]); 
// AsyncCall返回一个IAsyncCall接口
//但是这个代码没有引用它

因此,一旦初始化部分完成,返回的接口的引用计数就递减为零。这样就释放了实现这个接口的对象:

 析构函数TAsyncCall.Destroy; 
begin
如果FCall没有
开始
尝试
- > FCall.Sync; //抛出引发的异常
finally
FCall.Free;
结束
结束
继承了Destroy;
结束

密钥线是调用同步这迫使异步调用被执行完成。所有这一切都发生在主要线程中,它解释了您报告的行为。






解决方案是,您只需要保留 IAsyncCall 接口存储在一个变量中。

  var 
a:IAsyncCall;

初始化
a:= AsyncCall(@Load,[]);

在真正的代码中,您需要确保加载在运行任何依赖于 Load 的代码之前已经完成。当您的程序达到要求加载被调用的位置时,必须在<$ c上调用同步 $ c> IAsyncCall 界面。



所以你可以这样写。



<单位MyUnit pre>

界面

程序EnsureLoaded;

执行

使用
AsyncCalls;

....

程序加载;
begin
....
end;

var
LoadAsyncCall:IAsyncCall;

procedure EnsureLoaded;
begin
LoadAsyncCall:= nil; //这将会调用Sync
end;

初始化
LoadAsyncCall:= AsyncCall(@Load,[]);

结束。

来自所需其他单位的电话 EnsureLoaded 加载以运行。或者,可以从 MyUnit 导出的任何方法调用 EnsureLoaded ,这取决于加载已运行。后一种选择具有更好的封装。


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.

解决方案

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.

这篇关于AsyncCall与Delphi 2007的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆