5

TMyThreadというスレッドがあり、次のようにExecuteプロシージャをオーバーライドします。

 procedure TMyThread.Execute;
 Begin
     repeat
     //Some Work 
     Sleep(5000);
     //Some Work 2;
     Sleep(5000); 
     until FActive=False
 End;

メインフォームには、「DestroyMyThread」というボタンがあります。スレッドを破棄したいのですが、問題は、スレッドが動作を終了した場合にのみスレッドが破棄されることです。作業が終了していなくても、スレッドを破棄したい。どうすればよいですか?

4

3 に答える 3

23

スレッドのExecuteメソッドは、スレッドのTerminatedプロパティの状態を定期的にチェックする必要があります。の場合はTrue、スレッドExecuteメソッドを終了する必要があります。

したがって、一般的なExecute方法は次のようになります。

procedure TMyThread.Execute;
begin
  while not Terminated do
    DoNextPieceOfWork
end;

スレッドにはFActive、同じタスクを実行している独自のフラグがあるようです。それに関する問題はそれTThreadについて知らないということです。FActiveしたがって、組み込みのメカニズムを取り除き、代わりに使用する必要があります。

Freeスレッドを呼び出すと、が呼び出されますTerminate。それはに設定TerminatedされますTrue。次に、スレッドメソッドが終了するのを待ちます。これは、スレッドがそれを認識して終了するために発生しTerminatedますTrue。そして、スレッドのデストラクタは、スレッドを整理する作業を続行して終了できます。


Terminateあなたの答えのコードを見ると、既存のメカニズムを利用するように書かれたほうがよいでしょう。

type
  TMyThread = class(TThread)
  private
    FTerminateEvent: TEvent;
  protected
    procedure Execute; override;
    procedure TerminatedSet; override;
  public
    constructor Create(ACreateSuspended: Boolean);
    destructor Destroy; override;
  end;

constructor TMyThread.Create(ACreateSuspended: Boolean);
begin
  inherited Create(ACreateSuspended);
  FTerminateEvent := TEvent.Create(nil, True, False, '');
end;

destructor TMyThread.Destroy;
begin
  inherited;
  FTerminateEvent.Free;
end;

procedure TMyThread.TerminatedSet;
begin
  FTerminateEvent.SetEvent;
end;

procedure TMyThread.Execute;
begin
  while not Terminated do
  begin
    // do somthing interesting!
    FTerminateEvent.WaitFor(5000);
  end;
end;

Stopこれで、別のメソッドは必要ありません。Freeスレッドを呼び出すだけです。その後Terminate、と呼ばれます。そして、TerminatedSetと呼ばれます。次に、イベントが通知されます。その後、Execute終了します。そして、スレッドが消えることができます。


そうは言っても、5000ミリ秒のタイムアウトが最善のアプローチであるシナリオを考えるのに苦労しています。なぜこれをしているのかわかりませんが、スレッドが熱くならないようにスロットルを調整しようとしていると思います。ビジーループを避けたい。それは素晴らしいことですが、固定タイムアウトを使用することはそれを行う方法ではありません。これを行う方法は、同期イベント(通常はイベント)を待機することです。その後、実行する作業が増えると、イベントが通知され、スレッドがウェイクアップします。

于 2012-12-25T20:50:33.067 に答える
2

TEventを使用すると、この問題を解決できます。これは例です。

  uses SyncObjs;
  TMyThread = class(TThread)
       private
         FTerminateEvent: TEvent;
       protected
         procedure Execute; override  ;
       public
        constructor Create(ACreateSuspended: Boolean); overload;
        destructor Destroy; override;
        procedure Stop;
       end;
    constructor TMyThread.Create(ACreateSuspended: Boolean);
    begin
    FTerminateEvent := TEvent.Create(nil, True, False, 'FTerminateEvent');
    inherited Create(ACreateSuspended);
    end;

    destructor TMyThread.Destroy;
    begin
     FTerminateEvent.Free;
     inherited;
    end;

    procedure TMyThread.Stop;
    begin
    Terminate;
    FTerminateEvent.SetEvent;
    end;

    procedure TMyThread.Execute;
    begin
      while not Terminated do
      begin
      // do somthing interesting!
       FTerminateEvent.WaitFor(5000);
      end;
    end;

スレッドを強制終了したい場合は、MyThread.Freeを呼び出すよりも、MyThread.Stopを呼び出すだけです。

于 2012-12-26T00:18:46.650 に答える
1

あなたは本当にこの問題に完全に間違って取り組んでいます。スレッドをコーディングして、実行したい作業のみを実行するようにします。そうすれば、スレッドを制御するために「外部から手を差し伸べる」必要がなくなります。このスレッドは、実行したくないことを実行しているため、外部から制御する必要があると感じています。それでは、そもそもなぜそれを実行するようにコーディングしたのでしょうか。

于 2012-12-25T21:34:17.840 に答える