Question

Cette question peut sembler banal, mais j'espère que vous ne l'ignorer.
Avant de détruire un objet TThread il est généralement nécessaire d'attendre jusqu'à ce que le thread qui a appelé les finitions de la méthode TThread.Execute (), car alors seulement peut-on être sûr que, par exemple, les objets détruits à l'intérieur ne sont plus accessibles de destructor de la classe. Par conséquent, il est nécessaire d'appeler Terminate pour définir l'indicateur Terminated que le fil doit vérifier savoir si pour quitter ou non, puis appeler la méthode WaitFor ().

Parce que le fil peut être suspendu, je pense qu'il est bon de le reprendre avant d'appeler WaitFor, sinon le fil d'appel serait dans l'impasse. Et parce que le fil peut être suspendu plusieurs fois, il devrait reprendre le même nombre de fois, non?

while Suspended do
  Resume;

Si le fil a été créé en suspension, on n'a pas à craindre que la méthode TThread.Execute () est appelée lorsque nous reprenons le fil que d'y mettre fin - il ne sera pas (s'il vous plaît me corriger si je me trompe ).

Ce que je l'ai dit suggère d'utiliser les lignes de code suivantes pour chaque objet TThread être libéré:

MyThread.Terminate;
while MyThread.Suspended do
  MyThread.Resume;
MyThread.WaitFor;
MyThread.Free;

Malheureusement, lorsque nous détruisons notre application qui a créé plusieurs threads, écriture d'un tel morceau de code pour chaque TThread objet destruction rend inutilement le code très long et peut-être même opaque.

Par conséquent, je suis venu à la conclusion que tous ceux-ci pourraient être mis à l'intérieur d'une destructor surchargée de la classe TThread grâce à laquelle il suffirait d'appeler MyThread.Free (ou MyThread.Terminate si MyThread.FreeOnTerminate est réglé) sans se soucier de si l'objet détruit est un objet ou non TThread:

destructor TMyThread.Destroy;
begin
  //if FreeOnTerminate, the calling thread cannot wait for itself
  if GetCurrentThreadId <> ThreadId then
  begin
    Terminate;
    while Suspended do
      Resume;
    WaitFor;
  end;

  {free all objects created in this class}

  inherited Destroy;
end;

Pardonnez-moi de poser une telle question fondamentale. Je voudrais, cependant, d'apprendre à connaître votre opinion sur cette façon - je l'espère une façon universelle - de détruire des objets TThread. Je pose cette question car j'appris de mes codes de collègues de travail qu'ils utilisaient habituellement le premier exemple de code pour détruire ces objets, mais ils ne sont jamais utilisés pour vérifier si les fils étant attendu ne sont pas suspendus que je considérais un peu dangereux si les fils pourrait être suspendue quelque part dans le code. J'ai donc essayé de trouver un moyen universel de détruire les objets de cette classe qui rendrait le code plus clair et plus sûr. J'espère que je ne l'ai pas pire - que pensez-vous

?

Merci pour vos suggestions à l'avance.

Était-ce utile?

La solution

Une grande partie de ce que votre suggérant est déjà effectué dans le destructor de TThread.Destroy, et invoquer TMyThread.free fera tout ce que votre suggérer. Pour le nettoyage des objets appartenant à la classe de fil, vous pouvez effectuer qu'en cas OnTerminate, qui s'invoquée dans le cadre de la logique d'arrêt du fil.

Autres conseils

Il n'y a pas de méthode universelle pour arrêter un fil, comme il n'y a aucun moyen universel (gracieusement) arrêter un processus. Chacun est différent.

Pour certains sujets, il est suffisant pour définir sa propriété Terminated via la méthode Terminate. D'autres fils, cependant, les fonctions d'appel comme GetMessage ou MsgWaitForMultipleObjects, qui bloqueront jusqu'à ce que quelque chose arrive, comme un message arrivant ou une poignée de noyau devenir signalaient. TThread.Terminate ne peut pas faire l'une de ces choses se produisent, il ne peut pas faire ces fils arrêtent en cours d'exécution. Quand j'ai fils écrit comme ceux, j'ai fourni mes propres fonctions pour les informer de cesser de courir. Je pourrais appeler PostThreadMessage pour forcer un message sur la file d'attente du fil, ou je pourrais signaler l'événement que la classe de fil a prévu pour lui notifier une demande de mettre fin.

Ne vous inquiétez pas de reprendre un fil suspendu. Vous ne devriez pas vraiment les interrompez de toute façon. La seule façon sûre de suspendre un fil est pour le fil de se suspendre, et une fois que vous avez, vous êtes assuré d'avoir au moins deux fils de contrôle lors de l'exécution de fil: le fil lui-même de la suspendre, et au moins un autre du fil pour le reprendre à nouveau. Un fil doit être dans le contrôle de sa propre exécution.

Ce serait formidable si TThread.Terminate était virtuelle. Ensuite, chaque classe de fil pourrait fournir un moyen personnalisé de s'informer qu'il devrait cesser de courir. Certains opérateurs peuvent tout Terminated, et d'autres pourraient s'envoyer des messages, des événements de signal, ou faire tout ce dont ils ont besoin. Comme il est, cependant, la méthode non virtuelle ne fonctionne pas bien avec des fils qui passent beaucoup de leur temps d'attente pour d'autres choses. La façon actuelle ne fonctionne que pour les fils qui peuvent souvent sondage leurs propriétés Terminated.

Certains sujets ont leurs propriétés FreeOnTerminate défini. Pour ces fils, votre code n'est pas sûr. Techniquement, ce n'est pas sûr d'appeler any méthodes sur ces objets car le fil peut se terminer à tout moment. Mais même si vous savez que le fil est toujours en cours d'exécution et l'objet thread existe toujours, l'objet s'arrêtera certainement déjà quelque temps après l'appel à Terminate. Vous ne pouvez pas appeler WaitFor sur un objet sans fil en fin, et vous pouvez certainement pas appeler Free.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top