Démontrer différentes façons d'utiliser des threads à Delphi

Beaucoup trop d'utilisateurs de Delphi font l'erreur de penser un fil est une sorte de magie qui améliorera les performances de leur application. Malheureusement, c'est loin d'être vrai. La plus grande erreur n ° 1 lorsque vous essayez d'implémenter un thread, le fait accéder directement aux contrôles visuels de l'application. Mais ces contrôles visuels ne peuvent fonctionner que dans le contexte du thread principal de l'application. L'utilisation d'un autre thread pour mettre à jour les contrôles dans l'interface utilisateur doit être très soigneusement planifiée et implémentée. Et dans la plupart des cas, ce n'est probablement pas du tout la bonne solution au problème.
Autrement dit, le cadre VCL de Delphi n'est pas sûr de fil. Bien qu'il existe de nombreuses façons d'intégrer un fil dans votre interface utilisateur, il n'y a pas de solution unique. Cela variera toujours en fonction de ce que vous essayez d'accomplir. La plupart du temps, les gens veulent accomplir de meilleures performances (vitesse). Mais cela est très rarement fait en utilisant un fil. Au lieu de cela, les scénarios les plus courants où un thread est intégré dans une interface utilisateur est de maintenir cette interface utile pendant une longue tâche.
Pour cela, nous imaginerons une application simple avec un seul bouton qui télécharge un fichier depuis Internet lorsqu'il est cliqué. L'application a déjà un thread principal qui est utilisé pour toute l'interface utilisateur. Sur la plate-forme Windows, cela signifie envoyer / recevoir des messages Windows, dessin sur une toile de contrôle, reconnaître l'interaction utilisateur, etc. Ce thread est essentiellement une boucle géante qui tourne très rapidement. Pour chaque révolution de ce fil de filage, certains morceaux de code sont exécutés.
Dans un environnement fileté unique, ce téléchargement de fichiers bloquerait cette boucle de Spinning, jusqu'à ce que le téléchargement soit terminé. Pendant ce temps, ce fil n'est plus en mesure de faire des mises à jour d'interface utilisateur, de détecter les clics de l'utilisateur ou quoi que ce soit. C'est ce qui provoque la mise à la place de Windows (ne répond pas) dans le titre de telles formes, car, bien, tout comme elle le dit, il ne répond pas.
C'est là que les fils supplémentaires entrent en jeu. Il doit répondre aux fenêtres. Au lieu de bloquer le thread d'interface utilisateur principal avec ce téléchargement de fichier géant, vous pouvez mettre ce téléchargement de fichier dans un autre thread. C'est juste aussi simple, non?
Vous pouvez vous demander "comment puis-je surveiller les progrès?" ou "Comment puis-je être informé quand cela est fait?" Cela signifierait que le fil de téléchargement doit interagir en quelque sorte avec le fil principal. C'est exactement là que la confusion entre. Il y a maintenant deux boucles distinctes, et lorsque vous voulez mettre à jour l'interface utilisateur, ce fil d'interface utilisateur pourrait être n'importe où faire n'importe quoi. Plus important encore, supposons que le fil d'interface utilisateur principal soit en train d'écrire une chaîne sur la même propriété de contrôle que votre autre fil souhaite également écrire. Vous avez maintenant deux fils qui tentent d'écrire à la même adresse mémoire, ce qui peut entraîner des problèmes imprévisibles.
Par synchronisation. La classe TThread de Delphi a une méthode Synchronize () qui permet à un fil d'interagir avec le fil d'interface utilisateur principal uniquement à un moment où il se comportera correctement, quand il s'attend réellement à une telle occurrence. Le code qui est synchronisé à partir d'un autre thread ne s'exécute pas réellement dans le contexte de ce thread - il s'exécute toujours dans le contexte du thread d'interface utilisateur principal. C'est l'idée de synchroniser (), est d'exécuter du code dans le thread d'interface utilisateur.
Donc, à la fin, vous n'utilisez pas réellement le VCL du fil. Au lieu de cela, votre thread envoie un signal au thread principal, et ce n'est que lorsque le thread principal est prêt, il exécutera ce code. Pendant ce temps, votre fil secondaire est ensuite bloqué pendant qu'il attend que le fil principal se termine.
Ensuite, il y a l'erreur de penser qu'une grande opération d'interface utilisateur serait mieux dans un fil. Disons que vous avez une liste où vous souhaitez peupler des millions d'articles. Bien sûr, cela prendra du temps, et pendant ce temps, votre demande ne répondra pas. Encore. Alors déplacez ce code vers un fil, non?
Encore une fois, toute interaction UI doit être effectuée à partir du fil principal et le fil principal uniquement. Les threads sont utiles si vous avez besoin d'effectuer de longs calculs, de traiter des quantités massives de données, d'attendre une réponse à partir d'une ressource distante, ou autrement tout ce qui prend du temps et non directement lié à l'interface utilisateur.
C'est difficile à dire. Mais il y a une pratique courante qui est fortement conseillé lors de l'écriture d'un fil: mettez votre code de thread dans une unité qui lui est propre. Cette unité doit être isolée de toute autre unité d'interface utilisateur. Il ne devrait même pas avoir d'unité liée à VCL dans sa clause d'utilisation. Le fil ne devrait même pas savoir comment il est utilisé. Ce devrait être essentiellement un mannequin, dans le seul but d'effectuer votre longue tâche. En ce qui concerne les mises à jour de l'interface utilisateur d'un fil, cela est mieux accompli par les événements synchronisés.
Exactement à quoi cela ressemble. C'est un événement qui est synchronisé, comme expliqué précédemment. Un événement est simplement un pointeur vers une procédure que vous pouvez attribuer au fil avant son début. À l'intérieur du fil, lorsque vous devez mettre à jour l'interface utilisateur, vous utiliseriez ensuite Synchronize () pour déclencher cet événement. Avec cette conception, le fil n'aurait jamais à savoir qu'il est même utilisé par une interface utilisateur. En même temps, vous accomplissez également par inadvertance l'abstraction. Le fil devient réutilisable. Vous pouvez le brancher sur un autre projet qui pourrait même ne pas avoir d'interface utilisateur (disons un service Windows).
Voici quelques liens directs vers des ressources connexes sur la sécurité des threads VCL, au cas où vous ne voudrez pas rechercher ...
Cette application démontre l'utilisation des threads à Delphi. Puisqu'il y a beaucoup de choses différentes à savoir, elles sont divisées en différentes sections à des fins différentes. Chaque sujet a au moins 1 unité de formulaire (intégrée dans une feuille d'onglet) et au moins 1 unité autonome contenant sa fonctionnalité en dehors de l'interface utilisateur. Cela se fait exprès, pour montrer que les fils doivent être isolés de toute interface utilisateur.
La forme principale elle-même n'a pas de logique. Tout ce qu'il fait est d'intégrer les formulaires en onglets. Dans le gestionnaire d'événements FormCreate() , il fait de nombreux appels à EmbedForm() qui instancie un formulaire pour chaque feuille d'onglet.
L'utilisation de l'application est très simple. Vous vous rendez simplement à l'un des onglets, et chacun aura ses propres instructions.


Affiche comment un fichier peut être téléchargé à partir d'Internet dans un fil. Il existe une seule fonction universelle définie DownloadFile() qui effectue le téléchargement. L'interface utilisateur a 3 boutons:
Par défaut, l'URL à télécharger est un fichier de test fourni par ThinkBroadband.com, mais vous pouvez utiliser n'importe quelle URL que vous souhaitez. Vous pouvez également choisir l'emplacement pour enregistrer le fichier. Il s'agit d'une démo très simple, donc le nom de fichier / extension du nom de fichier local doit être ajusté à vos besoins - il ne changera pas automatiquement pour l'URL que vous téléchargez (comme les navigateurs le font généralement).

Montre comment mettre à jour une barre de progression à partir d'un fil qui effectue une longue tâche.

Démontre à l'aide d'une connexion de base de données dans un thread et de synchroniser les données avec le thread d'interface utilisateur.

Démontre plusieurs threads consommant des cycles CPU massifs pour charger de tester votre processeur.