7

この質問には、Delphi と XE が特に Suspend と Resume を廃止することが含まれます。私は他の投稿を読みましたが、これまでのところ同様の使用法を見つけていないので、先に進んで議論を求めます.

私が知りたいのは、スレッドが必要ないときにスレッドを一時停止するより良い方法はありますか?

何年も使用してきた Delphi クラスがあります。これは基本的に、スレッド化されたプロセスに関連付けられた FIFO キューです。キューはメイン スレッドでデータ オブジェクトを受け入れ、スレッドが中断されている場合は再開します。

スレッドの実行プロセスの一部として、オブジェクトはキューから取り出され、スレッド上で処理されます。通常、これはデータベース ルックアップを行うためのものです。

プロセスの最後に、オブジェクトのプロパティが更新され、メイン スレッドで使用できるようにマークされるか、別のキューに渡されます。実行プロセスの最後の (実際には最初の) ステップは、キューにアイテムがまだあるかどうかを確認することです。ある場合は続行し、そうでない場合は一時停止します。

それらのキーは、実行ループが完了したときに実行ループ内にある唯一の中断アクションであり、通常の操作中の唯一の再開は、新しいアイテムがキューに配置されたときに呼び出されます。例外は、キュー クラスが終了している場合です。

レジューム機能はこんな感じ。

process TthrdQueue.MyResume();
  begin
    if Suspended then begin
      Sleep(1); //Allow thread to suspend if it is in the process of suspending
      Resume();
    end;
  end;

実行はこれに似ています

process TthrdQueue.Execute();
  var
    Obj : TMyObject;
  begin
    inherited;
    FreeOnTerminate := true;
    while not terminated do begin
      if not Queue.Empty then begin
        Obj :=  Pop();
        MyProcess(Obj);  //Do work
        Obj.Ready := true;
      end
      else
        Suspend();  // No more Work
    end;   //Queue clean up in Destructor
  end;  

TthrdQueue Push ルーチンは、スタックに別のオブジェクトを追加した後、MyResume を呼び出します。MyResume は、スレッドが中断されている場合にのみ Resume を呼び出します。

シャットダウンするときは、terminate を true に設定し、中断されている場合は MyResume を呼び出します。

4

3 に答える 3

7

TthrdQueueの次の実装をお勧めします。

type
  TthrdQueue = class(TThread)
  private
    FEvent: THandle;
  protected
    procedure Execute; override;
  public
    procedure MyResume;
  end;

implementation

procedure TthrdQueue.MyResume;
begin
  SetEvent(FEvent);
end;

procedure TthrdQueue.Execute;
begin
  FEvent:= CreateEvent(nil,
                       False,    // auto reset
                       False,    // initial state = not signaled
                       nil);
  FreeOnTerminate := true;
  try
    while not Terminated do begin
      if not Queue.Empty then begin
        Obj :=  Pop();
        MyProcess(Obj);  //Do work
        Obj.Ready := true;
      end
      else
        WaitForSingleObject(FEvent, INFINITE);  // No more Work
    end;
  finally
    CloseHandle(FEvent);
  end;
end;
于 2010-12-09T18:02:20.273 に答える
3

スレッドを中断する代わりに、スレッドをスリープさせます。待機可能なハンドルでブロックし、ハンドルがシグナル状態になると、スレッドが起動します。

イベント、ミューテックス オブジェクト、セマフォ、メッセージ キュー、パイプなど、待機可能なオブジェクトには多くのオプションがあります。

イベントを使用することを選択したとします。自動リセット イベントにします。キューが空になったら、イベントのWaitForメソッドを呼び出します。他の何かがキューに入力したり、終了したい場合は、イベントのSetEventメソッドを呼び出します。

私が好む手法は、OS メッセージ キューを使用することです。キュー オブジェクトをメッセージに置き換えます。次に、標準GetMessageループを作成します。キューが空になると、新しいメッセージを待つために自動的にブロックされます。終了要求を別のメッセージに変えます。(このTThread.Terminateメソッドは、仮想ではないため、スレッドで興味深いことを始めると、あまり便利な機能ではありません。)

于 2010-12-09T18:04:10.723 に答える
3

条件変数を使用して、Delphiでプロデューサー/コンシューマー キューを実装できるようにするライブラリがあります。このシナリオは、実際に説明されている例です。

条件変数の典型的な例は、生産者/消費者の問題です。プロデューサーと呼ばれる 1 つ以上のスレッドがアイテムを生成し、それらをキューに追加します。コンシューマー (他のスレッド) は、生成されたアイテムをキューから削除することでアイテムを消費します。

于 2010-12-09T18:09:13.940 に答える