簡體   English   中英

如何按需啟動/停止監視Delphi線程?

[英]How to start/stop a monitoring Delphi thread on demand?

我一直在尋找一種方法來監視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;

在我的應用程序中,我將需要按需啟動和停止該線程,但是上面的代碼不允許這樣做。 僅設置終止標志將不會。

只要以某種方式告訴線程停止等待,然后釋放它並在需要時創建一個新線程就足夠了。 我如何更改此代碼以實現該目標?

使用帶有兩個事件的數組的WaitForMultipleObjects()而不是WaitForSingleObject() 將手動重置事件添加到線程類,並將Terminated設置為True后發出信號。 檢查返回值已發出兩個事件的信號,並采取相應措施。

編輯:

一些最小的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;

您只需要在問題中添加代碼即可。 只需嘗試釋放線程實例即可完成解除線程阻塞的所有必要操作(如有必要)。

相反,在INFINITE中,應在一段時間后使WaitForSingleObject超時。 這樣,循環將繼續並檢查終止。

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現在所承認的那樣,使用它們並不安全。 請參閱Delphi-2010中不推薦使用的TThread.resume應該在什么地方使用? http://msdn.microsoft.com/en-us/library/ms686345%28VS.85%29.aspx

這可以工作,只需進行如下較小的更改,現在就調用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;

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM