16

この質問は些細なことのように思えるかもしれませんが、無視しないでください。
通常、TThread オブジェクトを破棄する前に、TThread.Execute() メソッドを呼び出したスレッドが終了するまで待機する必要があります。これは、たとえば、クラスのデストラクタ内で破棄されたオブジェクトがアクセスされなくなったことを確認できるからです。したがって、Terminate を呼び出して終了するかどうかを知るためにスレッドがチェックする必要のある Terminated フラグを設定してから、WaitFor() メソッドを呼び出す必要があります。

スレッドが一時停止している可能性があるため、WaitFor を呼び出す前にスレッドを再開するのがよいと思います。そうしないと、呼び出し元のスレッドがデッドロックしてしまいます。また、スレッドは複数回中断できるため、同じ回数だけ再開する必要がありますよね?

while Suspended do
  Resume;

スレッドがサスペンド状態で作成された場合、スレッドを終了するためだけにスレッドを再開するときに TThread.Execute() メソッドが呼び出されることを心配する必要はありません (間違っていたら訂正してください)。

私が述べたことは、解放される各 TThread オブジェクトに対して次のコード行を使用することを提案しています。

MyThread.Terminate;
while MyThread.Suspended do
  MyThread.Resume;
MyThread.WaitFor;
MyThread.Free;

残念ながら、複数のスレッドを作成したアプリケーションを破棄する場合、破棄される TThread オブジェクトごとにそのようなコードを不必要に記述すると、コードが非常に長くなり、場合によっては不透明になります。

したがって、これらすべてを TThread クラスのオーバーライドされたデストラクタ内に配置できるという結論に達しました。そのおかげで、破棄されたかどうかを気にせずに MyThread.Free (または MyThread.FreeOnTerminate が設定されている場合は MyThread.Terminate) を呼び出すだけで十分です。 object が TThread オブジェクトかどうか:

destructor TMyThread.Destroy;
begin
  //if FreeOnTerminate, the calling thread cannot wait for itself
  if GetCurrentThreadId <> ThreadId then
  begin
    Terminate;
    while Suspended do
      Resume;
    WaitFor;
  end;

  {free all objects created in this class}

  inherited Destroy;
end;

こんな初歩的な質問ですみません。ただし、TThread オブジェクトを破棄するこの方法 (普遍的な方法であることを願っています) について、あなたの意見を知りたいと思います。同僚のコードから、彼らは通常、最初のコード例を使用してそのようなオブジェクトを破棄することを学びましたが、待機中のスレッドが中断されていないかどうかを確認することは一度もありませんでした。コードのどこかで中断されている可能性があります。したがって、コードをより明確かつ安全にする、このクラスのオブジェクトを破棄する普遍的な方法を見つけようとしました。私はそれを悪化させなかったことを願っています - あなたはどう思いますか?

事前にご提案いただきありがとうございます。

4

2 に答える 2

8

プロセスを (正常に) 停止する普遍的な方法がないように、スレッドを停止する普遍的な方法はありません。それぞれが異なります。

一部のスレッドでは、メソッドTerminatedを介してそのプロパティを設定するだけで十分です。Terminateただし、他のスレッドは、GetMessageまたはのような関数を呼び出します。これらの関数MsgWaitForMultipleObjectsは、メッセージが到着するか、カーネル ハンドルがシグナル状態になるなど、何かが発生するまでブロックされます。TThread.Terminateこれらのいずれかを発生させることはできないため、これらのスレッドの実行を停止させることはできません。このようなスレッドを作成したとき、実行を停止するように通知するための独自の関数を提供しました。メッセージを強制的にスレッドのキューに入れるために呼び出しPostThreadMessageたり、終了要求をスレッド クラスに通知するためにスレッド クラスが提供したイベントを通知したりします。

中断されたスレッドの再開について心配する必要はありません。とにかく、それらを一時停止するべきではありません。スレッドを一時停止する唯一の安全な方法は、スレッド自体を一時停止することです。これがあれば、スレッドの実行時に制御するスレッドが少なくとも 2 つあることが保証されます。スレッドを再開します。スレッドは、独自の実行を制御する必要があります。

TThread.Terminate仮想だったら最高です。次に、各スレッド クラスは、実行を停止する必要があることを自分自身に通知する独自の方法を提供できます。を設定するだけの人もいればTerminated、メッセージを投稿したり、イベントを通知したり、必要なことを何でもできる人もいます。ただし、そのままでは、非仮想メソッドは、他のことを待機するために多くの時間を費やすスレッドではうまく機能しません。現在の方法は、プロパティを頻繁にポーリングできるスレッドに対してのみ機能しTerminatedます。

一部のスレッドには、FreeOnTerminateプロパティが設定されています。これらのスレッドの場合、コードは安全ではありません。技術的には、スレッドはいつでも終了する可能性があるため、そのようなオブジェクトでメソッドを呼び出すことは安全ではありません。しかし、スレッドがまだ実行中であり、スレッド オブジェクトがまだ存在していることがわかっている場合でも、オブジェクトは、Terminate. WaitForフリー オン ターミネート スレッド オブジェクトを呼び出すことはできませんFree

于 2009-07-07T14:57:22.720 に答える