Question

Je cherchais un moyen de surveiller les changements de registre spécifiques à Delphi. Trouvé une solution à 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;

Dans ma demande, je devrai commencer et d'arrêter ce fil à la demande, mais le code ci-dessus ne le permet pas. couchait le drapeau Terminated ne le fera pas.

Il suffirait de dire en quelque sorte le fil de cesser d'attendre, puis libérer et créer un nouveau en cas de besoin. Comment puis-je changer ce code pour y parvenir?

Était-ce utile?

La solution

Utilisation WaitForMultipleObjects() avec un tableau de deux événements au lieu de WaitForSingleObject(). Ajouter un événement de réarmement manuel à la classe de fil, et le signal après avoir mis Terminated à True. Vérifiez la valeur de retour qui des deux événements a été signalé, et agir en conséquence.

Modifier

Certains minimal code Delphi 2009 pour démontrer l'idée. Vous devez ajouter SyncObjs à la liste des unités utilisées et ajouter

  fTerminateEvent: TEvent;

à la section private de votre classe de fil.

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;

Il vous suffit d'ajouter le code dans votre question à elle. Il suffit d'essayer de libérer l'instance de fil fera tout le nécessaire pour débloquer le fil (si nécessaire).

Autres conseils

Au lieu de INFINITE vous devriez avoir le temps WaitForSingleObject après une période. De cette façon, la boucle continue et des cessations est cochée.

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;

pourraient théoriquement être utilisés Les méthodes TThread.Suspend et TThread.Resume à des fils d'arrêt temporaire, mais comme Delphi 2010 reconnaît maintenant, ils ne sont pas sans danger pour l'utilisation. Voir TThread.resume est dépréciée Delphi-2010 ce qui devrait être utilisé à la place? et http://msdn.microsoft.com/en-us/library/ms686345%28VS.85%29.aspx

Cela fonctionne, il suffit de faire des petits changements comme ci-dessous et maintenant lorsque vous appelez 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;
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top