Comment démarrer / arrêter un contrôle Delphi fil sur la demande?
-
20-09-2019 - |
Question
Je cherchais un moyen de surveiller les changements de registre spécifiques à Delphi. Trouvé une solution à 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;
Dans ma demande, je devrai commencer et d'arrêter ce fil à la demande, mais le code ci-dessus ne le permet pas. couchait le drapeau Terminated ne le fera pas.
Il suffirait de dire en quelque sorte le fil de cesser d'attendre, puis libérer et créer un nouveau en cas de besoin. Comment puis-je changer ce code pour y parvenir?
La solution
Utilisation WaitForMultipleObjects()
avec un tableau de deux événements au lieu de WaitForSingleObject()
. Ajouter un événement de réarmement manuel à la classe de fil, et le signal après avoir mis Terminated
à True
. Vérifiez la valeur de retour qui des deux événements a été signalé, et agir en conséquence.
Modifier
Certains minimal code Delphi 2009 pour démontrer l'idée. Vous devez ajouter SyncObjs
à la liste des unités utilisées et ajouter
fTerminateEvent: TEvent;
à la section private
de votre classe de fil.
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;
Il vous suffit d'ajouter le code dans votre question à elle. Il suffit d'essayer de libérer l'instance de fil fera tout le nécessaire pour débloquer le fil (si nécessaire).
Autres conseils
Au lieu de INFINITE vous devriez avoir le temps WaitForSingleObject après une période. De cette façon, la boucle continue et des cessations est cochée.
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;
pourraient théoriquement être utilisés Les méthodes TThread.Suspend et TThread.Resume à des fils d'arrêt temporaire, mais comme Delphi 2010 reconnaît maintenant, ils ne sont pas sans danger pour l'utilisation. Voir TThread.resume est dépréciée Delphi-2010 ce qui devrait être utilisé à la place? et http://msdn.microsoft.com/en-us/library/ms686345%28VS.85%29.aspx
Cela fonctionne, il suffit de faire des petits changements comme ci-dessous et maintenant lorsque vous appelez 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;