Domanda

Sono stato alla ricerca di un modo per monitorare per le modifiche specifiche di registro a Delfi. Trovato un soluzione a 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;

Nella mia domanda ho bisogno di avviare e interrompere questa discussione su richiesta, ma il codice di cui sopra non permetterlo. Basta impostare il flag Terminato non lo farà.

Sarebbe sufficiente qualche modo dire al thread per smettere di aspettare, poi liberarlo e crearne uno nuovo quando necessario. Come posso cambiare questo codice per ottenere questo?

È stato utile?

Soluzione

Usa WaitForMultipleObjects() con una serie di due eventi invece di WaitForSingleObject(). Aggiungere un evento reset manuale alla classe filo, e segnalarlo dopo aver impostato Terminated a True. Controllare il valore di ritorno che dei due eventi è stato segnalato, e agire di conseguenza.

Modifica

Alcuni codice minimo Delphi 2009 per dimostrare l'idea. È necessario aggiungere SyncObjs alla lista delle unità utilizzate, e aggiungere

  fTerminateEvent: TEvent;

alla sezione private della classe thread.

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;

Hai solo bisogno di aggiungere il codice nella sua domanda ad esso. Semplicemente cercando di liberare l'istanza filo farà tutto il necessario per sbloccare il filo (se necessario).

Altri suggerimenti

Invece in INFINITE si dovrebbe avere il tempo WaitForSingleObject dopo un periodo. In questo modo il ciclo continua e terminati sia selezionata.

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;

Il TThread.Suspend metodi e TThread.Resume potrebbe teoricamente essere utilizzati per le discussioni di arresto temporaneo, ma come Delphi 2010 ora riconosce che non sono sicuri per l'uso. Vedere TThread.resume è deprecato a Delfi del 2010 quello che dovrebbe essere utilizzato in sostituzione? e http://msdn.microsoft.com/en-us/library/ms686345%28VS.85%29.aspx

Questo funziona, basta fare piccole modifiche, come di seguito e ora quando si chiama 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;
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top