5

新手问题:我有一个表单应用程序。它有一个单独的线程进行 Web 服务调用,然后将调用结果发布到主窗体。

在我的线程中,经过 X 秒后(使用 TTimer),我调用:

procedure TPollingThread.OnTimer(Sender: TObject);
var
SystemProbeValues : TCWProbeValues;  
begin
SystemProbeValues := Remote.Run.GetSystemProbeValues;
PostMessage( ParentHandle, WM_APIEVENT ,Integer(apiMultiCellStatus), Integer(SystemProbeValues) );
end;

函数 Remote.Run.GetSystemProbeValues 具有以下原型:

function GetSystemProbeValues : TCWProbeValues; stdcall;

TCWProbeValues 是 TCWProbeValue 对象的动态数组(它们都来自 TRemotable)。

在我的主要形式中,我收到了很好的消息并将 LParam 转换回 TCWProbeValues:

procedure TFrmCWMain.OnAPIEvent(var msg: TMessage);
begin
ProbeValues := TCWProbeValues(msg.LParam);
end;

我的问题是,鉴于动态数组及其对象是由 Delphi HTTORIO 系统创建的,谁负责释放它们?在我的 OnTimer 函数返回后,Delphi 是否认为该内存可重用?(在这种情况下,我的主窗体消息处理程序实际上可以读取消息的 LParam 引用的内存,这纯粹是幸运的吗?)或者更确切地说,释放由 HTTPRIO 请求自动实例化的对象是我的责任吗?

非常感谢,如果以上需要更多详细信息/代码,请大喊大叫,我会添加!

干杯,邓肯

4

1 回答 1

4

TRemotable通过其DataContext属性提供生命周期管理,因此 SOAP 运行时将释放对象本身。只要数据上下文对象存在,它分配的所有内容也将存在。如果您想声明对某个对象的所有权和责任,只需清除其DataContext属性即可。(这可能是您在这种情况下想要做的,因为您的 API 事件消息可能会在 SOAP 事件终止后得到处理。)


您的代码中的一个问题是您正在通过发布的消息传递一个动态数组。当您的OnTimer过程返回给它的调用者时,被引用的动态数组SystemProbeValues的引用计数将递减。如果另一个线程还没有处理该消息(它可能还没有),那么动态数组可能在它开始处理该消息时已经被销毁。

解决此问题的简单方法是在不减少引用计数的情况下清除计时器事件处理程序中的引用,然后在消息处理程序中执行相反的操作。发布消息后,清除变量:

LParam(SystemProbeValues) := 0;

在您的消息处理程序中,清除全局ProbeValues变量的旧值并分配新值,如下所示:

ProbeValues := nil;
LParam(ProbeValues) := Msg.LParam;

潜伏在您的代码中的另一个问题可能是TTimer在非 VCL 线程中的使用。该类创建一个窗口句柄以在该类的所有实例之间共享。除非您的计时器线程是程序中唯一使用 的线程,否则您TTimer可能会遇到问题,或者函数在错误的线程中运行,或者函数根本没有运行。代替TTimer,您可以使用SetTimer手动创建操作系统计时器,或者您可以创建等待计时器,这可能更适合在不需要保持对用户操作的响应的线程中使用。

于 2010-03-29T14:56:04.053 回答