1

Delphi で特定のレジストリの変更を監視する方法を探していました。about.comで解決策を見つけました:

procedure TRegMonitorThread.Execute;
begin
  InitThread; // method omitted here
  while not Terminated do
  begin
    if WaitForSingleObject(FEvent, INFINITE) = WAIT_OBJECT_0 then
    begin
      fChangeData.RootKey := RootKey;
      fChangeData.Key := Key;
      SendMessage(Wnd, WM_REGCHANGE, RootKey, LongInt(PChar(Key)));
      ResetEvent(FEvent);

      RegNotifyChangeKeyValue(FReg.CurrentKey, 1, Filter, FEvent, 1);
    end;
  end;
end;

私のアプリケーションでは、このスレッドをオンデマンドで開始および停止する必要がありますが、上記のコードではそれが許可されていません。Terminated フラグを設定するだけでは不十分です。

何らかの方法でスレッドに待機を停止するように指示し、必要に応じてスレッドを解放して新しいスレッドを作成するだけで十分です。それを達成するためにこのコードを変更するにはどうすればよいですか?

4

3 に答える 3

8

WaitForMultipleObjects()の代わりに 2 つのイベントの配列で使用しWaitForSingleObject()ます。手動リセット イベントをスレッド クラスに追加し、 に設定Terminatedした後に通知しますTrue。2 つのイベントのどちらが通知されたかの戻り値を確認し、それに応じて対処します。

編集:

アイデアを示すための最小限の Delphi 2009 コード。SyncObjs使用済みユニットのリストに追加し、追加する必要があります

  fTerminateEvent: TEvent;

privateあなたのスレッドクラスのセクションに。

constructor TTestThread.Create;
begin
  inherited Create(TRUE);
  fTerminateEvent := TEvent.Create(nil, True, False, '');
  // ...
  Resume;
end;

destructor TTestThread.Destroy;
begin
  fTerminateEvent.SetEvent;
  Terminate; // not necessary if you don't check Terminated in your code
  WaitFor;
  fTerminateEvent.Free;
  inherited;
end;

procedure TTestThread.Execute;
var
  Handles: array[0..1] of THandle;
begin
  Handles[0] := ...; // your event handle goes here
  Handles[1] := fTerminateEvent.Handle;
  while not Terminated do begin
    if WaitForMultipleObjects(2, @Handles[0], False, INFINITE) <> WAIT_OBJECT_0 then
      break;
    // ...
  end;
end;

質問のコードを追加するだけです。スレッドインスタンスを解放しようとするだけで、スレッドのブロックを解除するために必要なすべてのことが行われます (必要な場合)。

于 2009-11-14T16:12:15.050 に答える
1

これは機能します。以下のように小さな変更を加えるだけで、Terminate を呼び出したときに次のようになります。

  TRegMonitorThread = class(TThread)
  ...
  public
    procedure Terminate; reintroduce;
...

procedure TRegMonitorThread. Terminate;  // add new public procedure
begin
  inherited Terminate;
  Windows.SetEvent(FEvent);
end;

procedure TRegMonitorThread.Execute;
begin
  InitThread;

  while not Terminated do
  begin
    if WaitForSingleObject(FEvent, INFINITE) = WAIT_OBJECT_0 then
    begin
      if Terminated then // <- add this 2 lines
        Exit;
      ...
    end;
  end;
end;
于 2009-11-14T19:01:58.763 に答える
1

INFINITE の代わりに、一定期間後に WaitForSingleObject をタイムアウトにする必要があります。そうすれば、ループが続き、Terminated がチェックされます。

procedure TRegMonitorThread.Execute;
begin
  InitThread; // method omitted here
  while not Terminated do
  begin
    if WaitForSingleObject(FEvent, 1000) = WAIT_OBJECT_0 then
    begin
      fChangeData.RootKey := RootKey;
      fChangeData.Key := Key;
      SendMessage(Wnd, WM_REGCHANGE, RootKey, LongInt(PChar(Key)));
      ResetEvent(FEvent);

      RegNotifyChangeKeyValue(FReg.CurrentKey, 1, Filter, FEvent, 1);
    end;
  end;
end;

メソッド TThread.Suspend および TThread.Resume は、理論的にはスレッドを一時的に停止するために使用できますが、Delphi 2010 では現在、これらのメソッドを安全に使用できないことが認められています。TThread.resume is deprecated in Delphi-2010 を参照してください。代わりに何を使用する必要がありますか? およびhttp://msdn.microsoft.com/en-us/library/ms686345%28VS.85%29.aspx

于 2009-11-14T16:03:25.427 に答える