5

初心者の質問:フォームアプリケーションがあります。Webサービス呼び出しを行い、呼び出しの結果をメインフォームに投稿する別のスレッドがあります。

私のスレッドでは、(TTimerを使用して)X秒が経過した後、次のように呼び出します。

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システムによって作成されたとすると、それらを解放する責任があるのでしょうか。Delphiは、OnTimer関数が戻った後、メモリが再利用可能であると見なしましたか?(そして、その場合、私のメインフォームメッセージハンドラーが実際にメッセージの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してOSタイマーを手動で作成するか、待機可能なタイマーを作成することができます。これは、ユーザーアクションに応答し続ける必要のないスレッドでの使用に適している場合があります。

于 2010-03-29T14:56:04.053 に答える