Pergunta

Eu estive procurando uma maneira de monitorar alterações específicas de registro em Delphi.Encontrei um solução no 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;

Na minha aplicação eu preciso para iniciar e parar a esta discussão sobre a demanda, mas o código acima não permite isso.Apenas a definição de Encerrado o sinalizador de não fazer.

Seria suficiente para, de alguma forma, dizer que o segmento de parar de espera e, em seguida, liberte-lo e criar um novo, quando necessário.Como posso modificar esse código para conseguir que?

Foi útil?

Solução

Usar WaitForMultipleObjects() com uma variedade de dois eventos em vez de WaitForSingleObject(). Adicione um evento de redefinição manual à classe Thread e sinalize depois de definir Terminated para True. Verifique o valor de retorno Qual dos dois eventos foi sinalizado e age de acordo.

Editar:

Algum código mínimo Delphi 2009 para demonstrar a ideia. Você tem que adicionar SyncObjs à lista de unidades usadas e adicionar

  fTerminateEvent: TEvent;

para o private Seção da sua aula de threads.

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;

Você só precisa adicionar o código em sua pergunta a ele. Simplesmente tentar libertar a instância do thread fará todo o necessário para desbloquear o thread (se necessário).

Outras dicas

Em vez disso, na INFINITA você deve ter WaitForSingleObject depois de um período.Dessa forma, o loop continua e Finalizado é verificada.

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;

Os métodos TThread.Suspender e TThread.Retomar poderia, teoricamente, ser usado para parada temporária threads, mas como Delphi 2010 agora reconhece que eles não são seguros para o uso.Ver TThread.currículo é preterido no Delphi 2010, o que deve ser usado no lugar? e http://msdn.microsoft.com/en-us/library/ms686345%28VS.85%29.aspx

Isso funciona, basta fazer pequenas alterações como abaixo e agora quando você liga para finalizar:

  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;
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top