delphi - termine tous les threads (TThread) à la fermeture de l'application
Question
Mon application est un serveur TCP / IP, avec le thread principal créé une seule fois & amp; écoute tout le temps. Lorsqu'un nouveau client se connecte, le thread principal crée le nouveau thread de type TClientThread
. Il n’existe cependant aucune liste de threads client en cours d’exécution, ce qui compliquerait un peu l’application de mon application. Existe-t-il un moyen quelconque d’exécuter " terminate " méthode sur tous les threads, même si le thread est occupé (dans mon cas, "occupé" signifie qu'il attend les données, le délai d'attente étant d'environ 30 secondes ... je dois donc le tuer quand même, sans attendre.) ?
L'application de fermeture simple ne semble pas exécuter "Terminer". méthode sur les threads, ce qui entraîne des fuites de mémoire signalées par FastMM ...
La solution
Les fuites de mémoire à l’arrêt ne vous inquiétez pas: vous libérer de la mémoire avant de rendre le contrôle au système d’exploitation est une perte de temps qui ralentit inutilement la fermeture des applications. Il vous suffit de vous assurer que toutes les données ont été enregistrées et que tous les descripteurs interprocess (tels que les sémaphores et les mutex) sont correctement libérés et sortent.
Pour notifier les clients, le mieux que vous puissiez faire serait une stratégie un peu comme ceci:
- Ajoutez tous les threads de gestion des clients à une liste quelque part (avec un verrouillage approprié pour la création, la destruction et l'itération)
- Demandez aux threads clients de se retirer de la liste lors de la résiliation et demandez au dernier élément de la liste de définir un événement (événement de réinitialisation manuelle, par exemple
TEvent
dans SyncObjs) si le serveur est en train de fermer - Introduisez une interrogation (par exemple,
select
ou un équivalent avec un délai d'attente) ou un autre type d'interruption (par exemple, SO_RCVTIMEO / SO_SNDTIMEO) dans ce qui serait autrement des routines de blocage de longue durée, surveillant la propriété Terminated - À l’arrêt, verrouillez la liste et parcourez-la en appelant
Terminate
, puis attendez que l’événement soit signalé; bien entendu, le socket d’écoute qui ajoute des éléments à la liste doit être fermé et connu pour être fermé avant de parcourir la liste
Autres conseils
Il semble que cet article puisse aider
Ce que vous verrez si vous cliquez sur ce lien:
Utilisation des sémaphores dans Delphi, partie 2: Le pool de connexion
Par: Cary Jensen
Résumé: Les sémaphores sont utilisés pour coordonner plusieurs threads et processus. Que les sémaphores fournissent plusieurs threads avec simultané l'accès à une ressource partagée est mis en évidence par le La classe TFixedConnectionPool décrite dans cet article.
J'utilise un KillThreadList: TList global. Je le surveille dans mon thread en tant que:
while (Not Terminated) do
begin
inc(Inker);
if (WaitForSingleObject(FTick, finterval) = WAIT_TIMEOUT) then
Begin
if Inker >= 10 then
Begin
ProcessTables;
Inker := 0;
sleep(1000);
End;
if KillThreadList.Contains(ThreadID) = True then Terminate;
End;
end;
Je teste également KillThreadList dans mes processus pour me permettre de les désactiver avant la fin du processus, même en toute sécurité.
Je transmets l'événement OnTerminate au thread principal et supprime le ThreadID de la KillList. J'utilise beaucoup ce modèle et il ne m'a pas encore échoué.
procedure TfrmProcessQualcommLocations.OnTerminateThread;
var
ThreadID : Cardinal;
i : integer;
aStatusBar :TStatFrame;
begin
ThreadID := (Sender as Tthread).ThreadID;
for i := 0 to StatusBarList.Count -1 do
Begin
if StatusBarList.Items[i].ThreadID = ThreadID then
Begin
aStatusBar := StatusBarList.Items[i];
KillThreadList.Extract(ThreadID);
StatusBarList.Extract(aStatusBar);
aStatusBar.Free;
break;
End;
End;
self.Refresh;
end;
Dans le cas ci-dessus, je supprime également certains éléments de l'interface graphique.
J'espère que ça aide. SpringerRider