Como iniciar/parar um monitoramento Delphi segmento em que procura?
-
20-09-2019 - |
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?
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;