Ils sont fondamentaux dans Windows. Alors pourquoi se priver de les utiliser ?
Un thread ... :
Mais surtout, une application qui utilise deux threads peut faire deux choses à la fois. Ce qui n'est généralement pas possible lors que vous développez une application sans gérer de threads (car il n'y a alors qu'un seul thread). Au passage, un processeur ne sait faire qu'une chose à la fois : Windows dispatche le travail, ce qui donne l'illusion d'un travail en simultané. C'est là que la priorité joue son rôle. Quel thread doit être exécuté prioritairement par rapport à un autre ? Par exemple, le gestionnaire de souris est plus important que votre application, et c'est normal. Votre application aura donc une priorité inférieure.
Une haute priorité assure également une meilleure régularité de vitesse d'exécution dans le cadre d'un traitement long.
Mais si un thread effectue des opérations périodiquement, il ne peut en aucun cas être assimilé à un TTimer, en raison de ses caractéristiques, de son fonctionnement et surtout de la régularité sans faille des threads (les TTimer sont peu précis et pas toujours exécutés au bon moment, voire pas du tout si l'application est en plein travail). J'ajouterai qu'avec un thread, vous pouvez chronométrer des temps même si un gros jeu en 3D est lancé, ce que n'aurait pas permis une méthode avec un TTimer.
Conclusion : avec un thread, le traitement des données est assuré de fonctionner toujours quels que soient les processus logés en mémoire. N'hésitez pas à regarder les exemples fournis avec Delphi. Ça peut donner des idées...
J'espère que vous êtes bons sur le développement des classes, car sinon il va falloir relire le tutoriel N°191.
Voici un thread fonctionnel dont le rôle est de ne rien faire... Oh ?
Créons une nouvelle unité que l'on va nommer "MonThread.pas". Copiez ce qui suit :
unit MonThread; interface uses Windows, Classes, SysUtils; type TPersoThread = class(TThread) private procedure CentralControl; public constructor Create(CreateSuspended:boolean); destructor Destroy; override; protected procedure Execute; override; end; implementation constructor TPersoThread.Create(CreateSuspended:boolean); begin inherited Create(CreateSuspended); FreeOnTerminate:=false; Priority:=tpNormal; end; destructor TPersoThread.Destroy; begin //déchargez la mémoire ici si vous avez créé des objets inherited; end; procedure TPersoThread.CentralControl; begin //écrivez ici ce que doit faire votre thread à un instant T donné end; procedure TPersoThread.Execute; begin repeat Sleep(500); //en millisecondes Synchronize(CentralControl); until Terminated; end; end.
Pour utiliser ce thread dans votre nouvelle application, il suffit de rajouter dans "Unit1.pas" tout ce qui est signalé en commentaires :
unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs, MonThread; // Ajouter : , MonThread; type TForm1 = class(TForm) private { Déclarations privées } public { Déclarations publiques } end; var Form1 : TForm1; MThrd : TMonThread; // ligne à ajouter implementation {$R *.DFM} initialization // ligne à ajouter MThrd:=TMonThread.Create(true); // ligne à ajouter finalization // ligne à ajouter MThrd.Free; // ligne à ajouter end.
Dans le cas ci-dessus, pour lancer le thread, il suffira de faire MThrd.Resume;
Pour suspendre le thread, il suffira de faire MThrd.Suspend;
C'est tout simple. Il faut que vous en soyez convaincu ;)
Reprenons notre fichier "MonThread.pas". Qu'y a-t-il dedans ?
Il y a déjà un héritage depuis TThread. Pour information :
TThread = class;
.
Le constructor public :
tpLowest
tpLower
tpNormal => valeur par défaut
tpHigher
tpHighest
tpTimeCritical => priorité absolue
tpIdle => dans les temps morts de l'application |
Le destructor public permet de libérer les objets qui auraient été créés dans le constructor : TStringList, TPanel... par exemple. S'il ne reste que inherited dans le destructor, vous pouvez faire disparaître le destructor (superflu).
Dans le thread, il nous faut une procédure privée qui effectuera une tâche périodiquement. Par exemple : tester l'existence d'un fichier et agir en conséquence, vérifier un paramètre système... etc.
Et enfin, il nous faut le corps crucial du thread : la procédure Execute. Il faut garder la structure qui est donnée ci-dessus. Le Sleep permet de suspendre temporairement le thread sans modifier ses propriétés internes. En fait, le Sleep est indispensable pour ne pas bloquer et figer tout le système d'exploitation. Ensuite, on appelle la procédure Synchronize dont on met en paramètre le nom de la procédure qui doit être exécutée. Vous allez me dire : pourquoi ne pas appeler directement la procédure passée en paramètre ? En fait, ça permet d'éviter les conflits du multi-threading (quand il y a plusieurs threads qui s'exécutent en parallèle). Si vous voulez paramétrer CentralControl, vous n'avez pas d'autres choix que de développer des propriétés. Enfin, on boucle Sleep et Synchronize tant que le thread est actif.
Passons maintenant au fichier "Unit1.pas"
Ici, on utilise qu'un seul thread. On déclare l'unité-squelette, la variable thread qui sera véritablement notre thread (pour l'instant, on n'avait développé que son squelette) et enfin on crée les blocs qui vont initialiser et détruire le thread respectivement quand l'application se lance et se ferme (merci INITIALIZATION...FINALIZATION).
Insistons sur le fait qu'un TMonThread.Create(true) crée un thread initialement arrêté. Pour le lancer, on utilise la procédure Resume. De même, TMonThread.Create(false) crée un thread initialement actif et qui doit subir la procédure Suspend pour l'arrêter sans le détruire.
Tanguy ALTERT,
http://altert.family.free.fr/