Comment résilier anonyme threads en Delphi sur demande à proximité?
J'ai une application Delphi, qui engendre le 6 anonyme threads sur un TTimer.Événement OnTimer.
Si je ferme l'application à partir du bouton X dans la barre de titre de Violation d'Accès à l'adresse $C0000005 est soulevé et FastMM rapports de fuite TAnonymousThread objets.
Qui est le meilleur moyen de anonyme gratuit threads en Delphi créé au sein événement OnTimer avec TThread.CreateAnonymousThread() la méthode?
SOLUTION qui a fonctionné pour moi:
Créé une enveloppe anonyme des threads qui met fin à être Libre-ed.
type
TAnonumousThreadPool = class sealed(TObject)
strict private
FThreadList: TThreadList;
procedure TerminateRunningThreads;
procedure AnonumousThreadTerminate(Sender: TObject);
public
destructor Destroy; override; final;
procedure Start(const Procs: array of TProc);
end;
{ TAnonumousThreadPool }
procedure TAnonumousThreadPool.Start(const Procs: array of TProc);
var
T: TThread;
n: Integer;
begin
TerminateRunningThreads;
FThreadList := TThreadList.Create;
FThreadList.Duplicates := TDuplicates.dupError;
for n := Low(Procs) to High(Procs) do
begin
T := TThread.CreateAnonymousThread(Procs[n]);
TThread.NameThreadForDebugging(AnsiString('Test thread N:' + IntToStr(n) + ' TID:'), T.ThreadID);
T.OnTerminate := AnonumousThreadTerminate;
T.FreeOnTerminate := true;
FThreadList.LockList;
try
FThreadList.Add(T);
finally
FThreadList.UnlockList;
end;
T.Start;
end;
end;
procedure TAnonumousThreadPool.AnonumousThreadTerminate(Sender: TObject);
begin
FThreadList.LockList;
try
FThreadList.Remove((Sender as TThread));
finally
FThreadList.UnlockList;
end;
end;
procedure TAnonumousThreadPool.TerminateRunningThreads;
var
L: TList;
T: TThread;
begin
if not Assigned(FThreadList) then
Exit;
L := FThreadList.LockList;
try
while L.Count > 0 do
begin
T := TThread(L[0]);
T.OnTerminate := nil;
L.Remove(L[0]);
T.FreeOnTerminate := False;
T.Terminate;
T.Free;
end;
finally
FThreadList.UnlockList;
end;
FThreadList.Free;
end;
destructor TAnonumousThreadPool.Destroy;
begin
TerminateRunningThreads;
inherited;
end;
Fin ici est de savoir comment vous pouvez l'appeler:
procedure TForm1.Button1Click(Sender: TObject);
begin
FAnonymousThreadPool.Start([ // array of procedures to execute
procedure{anonymous1}()
var
Http: THttpClient;
begin
Http := THttpClient.Create;
try
Http.CancelledCallback := function: Boolean
begin
Result := TThread.CurrentThread.CheckTerminated;
end;
Http.GetFile('http://mtgstudio.com/Screenshots/shot1.png', 'c:\1.jpg');
finally
Http.Free;
end;
end,
procedure{anonymous2}()
var
Http: THttpClient;
begin
Http := THttpClient.Create;
try
Http.CancelledCallback := function: Boolean
begin
Result := TThread.CurrentThread.CheckTerminated;
end;
Http.GetFile('http://mtgstudio.com/Screenshots/shot2.png', 'c:\2.jpg');
finally
Http.Free;
end;
end
]);
end;
Pas de fuites de mémoire, l'arrêt correct et facile à utiliser.
"anonyme threads" - Oh, génial.. qu'avez-Embarcadero imposé à nous maintenant?
Rien d'effrayant, vraiment. C'est un thread dont le comportement est fourni au moment de la création par une méthode anonyme. Il vous permet d'utiliser des fermetures lors de la définition des threads.
Il est continuellement créer/détruire des threads, quelque chose que je ai passé les 20 dernières années, de raconter, de développeurs afin d'éviter. Néanmoins, si ce n'est déjà commencé, je ne vois pas pourquoi il devrait y avoir un AV.
Gad, je suis sûr que ce n'est pas le adresse de la violation d'accès; $C0000005 Windows est le code d'exception pour des violations d'accès. S'il vous plaît copiez et collez le réel message d'erreur de texte. (Vous pouvez appuyer sur Ctrl+C dans la boîte de dialogue copier la totalité de la boîte de dialogue de texte.)
D'autres questions dans le nouveau code: Plutôt que de fuir, des fils qui se terminent par eux-mêmes pouvez obtenir la double-libéré. Depuis la méthode anonyme n'a pas de référence à l'objet thread, il ne peut pas vérifier la
Rien d'effrayant, vraiment. C'est un thread dont le comportement est fourni au moment de la création par une méthode anonyme. Il vous permet d'utiliser des fermetures lors de la définition des threads.
Il est continuellement créer/détruire des threads, quelque chose que je ai passé les 20 dernières années, de raconter, de développeurs afin d'éviter. Néanmoins, si ce n'est déjà commencé, je ne vois pas pourquoi il devrait y avoir un AV.
Gad, je suis sûr que ce n'est pas le adresse de la violation d'accès; $C0000005 Windows est le code d'exception pour des violations d'accès. S'il vous plaît copiez et collez le réel message d'erreur de texte. (Vous pouvez appuyer sur Ctrl+C dans la boîte de dialogue copier la totalité de la boîte de dialogue de texte.)
D'autres questions dans le nouveau code: Plutôt que de fuir, des fils qui se terminent par eux-mêmes pouvez obtenir la double-libéré. Depuis la méthode anonyme n'a pas de référence à l'objet thread, il ne peut pas vérifier la
Terminated
de la propriété, afin de l'appelant Terminate
ne fait rien. (L'appel de Free
appellerais Terminate
de toute façon.) Il n'y a aucune raison pour qu'un thread-safe liste car il n'est jamais accessible dans un seul thread. Avez-vous songé à l'aide de Revue de Code? Il fournit plus de place pour parler de code de ces commentaires.
OriginalL'auteur Ivelin Nikolaev | 2012-05-01
Vous devez vous connecter pour publier un commentaire.
Si vous voulez maintenir et d'exercer le contrôle sur un fil de la vie alors il doit avoir
FreeOnTerminate
ensemble deFalse
. Sinon c'est une erreur à consulter le fil après il a commencé à s'exécuter. C'est parce que une fois qu'il commence à s'exécuter, vous avez aucun moyen de savoir si oui ou non il a été libéré.L'appel à
CreateAnonymousThread
crée un thread avecFreeOnTerminate
ensemble deTrue
.Et, donc, mais par défaut, vous n'êtes pas en position d'exercer un contrôle sur le fil de la vie. Toutefois, vous pouvez définir
FreeOnTerminate
àFalse
immédiatement avant l'appel deStart
. Comme ceci:Cependant, je ne suis pas sûr que je le ferais. La conception de
CreateAnonymousThread
est que le fil est automatiquement libérée lors de la résiliation. Je pense que je personnellement, soit de suivre la conception, ou dériver de mon propreTThread
descendant.Lisez la documentation pour les anonymes fil. Vous n'êtes pas autorisé à maintenir une référence à l'TThread car il utilise FreeOnTerminate.
Désolé, je ne peux pas regarder ce projet. Je pense que j'ai répondu à la question que vous avez posée. Essentiellement, on vous démarrez un anonyme fil, vous perdez le contrôle. Vous ne pouvez plus faire référence.
Les documents mentionnés sont: docwiki.embarcadero.com/Libraries/XE2/en/...
Vous pouvez contrôler anonyme threads qu'il est normal de TThread il je viens de initialisé comme FreeOnTerminate ... comme je l'ai posté dans mon answear. Donc, vous devez éditer votre answear et enlever la partie qui dit "vous ne devez pas utiliser anonyme threads"
OriginalL'auteur David Heffernan
Pour éviter les erreurs à l'aide de
CreateAnonymousThread
juste misFreeOnTerminate
àFalse
avant le départ.De cette façon, vous pouvez travailler avec le fil comme vous le faites sans aucune solution de contournement.
Vous pouvez lire la documentation qui dit que
CreateAnonymousThread
définit automatiquementFreeOnTerminate
àTrue
et c'est ce qui est à l'origine des erreurs lorsque vous faites référence au thread.OriginalL'auteur Diego Garcia
Faire à votre threads de regarder pour certains type de notification de l'extérieur. Cela pourrait être un événement qui obtient signalé, un message envoyé à une fenêtre détenue par le fil, une commande envoyée sur une prise de votre thread d'écoute, ou de toute autre forme de communication que vous trouvez.
Si vous déterminez que ce problème est dû au fait que les threads sont dits "anonymes" threads, puis une solution simple pour vous est de les rendre non-anonyme threads. Mettre le corps de la fonction anonyme dans le
Execute
méthode, et de passer tout capturé les variables de la classe thread via son constructeur.Bien sûr, @David. N'est-ce pas
CreateAnonymousThread
la preuve? Et alors?Je veux dire que ce serait une alternative à l'approche proposée dans la dernière phrase de votre réponse.
OriginalL'auteur Rob Kennedy