Come avviare / fermare un monitoraggio filo Delphi su richiesta?
-
20-09-2019 - |
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?
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;