Cómo iniciar / detener un hilo de monitoreo de Delphi en la demanda?
-
20-09-2019 - |
Pregunta
He estado buscando una manera de controlar los cambios de registro específicas en Delphi. Encontrado un solución en 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;
En mi solicitud que tendrá que iniciar y detener este hilo en la demanda, pero el código anterior no permite eso. Sólo el establecimiento del indicador Terminado no lo hará.
Sería suficiente para decirle de alguna manera el hilo que dejar de esperar, a continuación, liberarla y crear uno nuevo cuando sea necesario. ¿Cómo puedo cambiar el código para lograr eso?
Solución
Uso WaitForMultipleObjects()
con una serie de dos eventos en lugar de WaitForSingleObject()
. Añadir un evento de rearme manual a la clase de hilo, y señalar que después de haber establecido Terminated
a True
. Comprobar el valor de retorno cuál de los dos eventos se ha señalado, y actuar en consecuencia.
Editar
Algunos mínima de código de Delphi 2009 para demostrar la idea. Usted tiene que agregar SyncObjs
a la lista de unidades usadas, y añadir
fTerminateEvent: TEvent;
a la sección private
de su clase de hilo.
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;
Sólo tiene que añadir el código en tu pregunta a la misma. Simplemente tratando de liberar la instancia hilo va a hacer todo lo necesario para desbloquear el hilo (si es necesario).
Otros consejos
En lugar de INFINITO usted debe tener tiempo WaitForSingleObject a cabo después de un período. De esta forma el bucle continúa y se comprueba Terminado.
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;
El TThread.Suspend métodos y TThread.Resume teóricamente podría ser utilizado para las discusiones parada temporal, sino como Delphi 2010 reconoce ahora que no son seguros para su uso. Ver TThread.resume está en desuso en Delphi-2010 lo que se debe utilizar en su lugar? y http://msdn.microsoft.com/en-us/library/ms686345%28VS.85%29.aspx
Esto funciona, sólo hacer pequeños cambios que a continuación y ahora cuando se llama Terminar:
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;