THREAD
Le parallélisme fait partie de notre quotidien. Il n'est pas rare d'exécuter plusieurs
actions en même temps : manger, écouter, écrire... Une telle approche peut-être utilisé en
programmation. De plus en plus de logiciels utilisent cette technique. Cette méthode est employée par
certains lecteurs vidéo et audio sur le Web. On peut ainsi écouter le fichier sans devoir
attendre qu'il soit totalement téléchargé. Un thread exécute le fichier, un autre
le télécharge.
Le système alloue un certain temps d'exécution à chaque tâche. Le temps alloué à chaque
programme est si court qu'on a l'impression que tout fonctionne simultanément. Un tel système
est dit multitâche de prémption.
Un thread est un sous-programme d'une application, c'est une unité d'exécution de
celui-ci. Plusieurs threads peuvent fonctionner en même temps dans une application.
L'utilisation des threads permet d'augmenter les performances.
Priorité
La priorité permet d'allouer un certain temps d'exécution aux threads. Les valeurs
suivantes peuvent être affectés à la propriété «Priority» du thread.
- tpIdle Le thread s'exécute seulement quand le système est en attente.
- tpLowest La priorité du thread est deux points en dessous de la normale.
- tpLower La priorité du thread est un point en dessous de la normale.
- tpNormal La priorité du thread est normale.
- tpHigher La priorité du thread est un point au-dessus de la normale
- tpHighest La priorité du thread est deux points au-dessus de la normale.
- tpTimeCritical Le thread a la priorité la plus élevée.
Il faut bien identifier les besoins qu'on a pour ne pas allouer trop de temps à un
thread qui attend des donnés de l'extérieur, on réduisait ainsi les performances au lieu
de les augmenter.
Synchronisation de base
Il a sa propre pile et les variables locales sont locales à chaque thread. Des données globabes
peuvent être partagées entre les différents threads, il peut donc avoir des problèmes de
synchronisation. S'il y a qu'un thread qui utilise une variable globale, il n'y a aucun problème.
Aperçu des méthodes
Création
Il faut créer un descendant de la classe TThread
Execute
Cette méthode est abstraite, elle contiendra le code à exécuter lorsque le thread débutera.
Terminated
Cette propriété et la méthode Terminate permettent d'arrêter un thread.
Suspended
En affectant true à cette propriété ou en appelant la méthode Suspend, le thread sera suspendu.
Resume
Cette méthode reprend l'exécution d'un thread interrompu.
Synchronize
Cette méthode sert à exécuter une méthode dans le thread principal de la vcl. On évite
de nombreux conflits lors du multi-thread en l'employant. La synchronisation peut s'avérer nécessaire
lorsqu'on utilise des objets de la vcl/clx.
L'unité classes doit être incluse dans la partie uses.
Ce thread servira à afficher le nombre de fois qu'il est passé dans une boucle.
type
TLoop = class(TThread)
private
cptIteration : integer;
protected
constructor create();
procedure Execute; override;
procedure ReAfficher;
end;
Nous sommes obligés de définir la méthode execute.
procedure TLoop.Execute;
begin
while (not Terminated) do begin
inc(cptIteration);
Synchronize(ReAfficher);
end;
end;
Destruction de thread
Afin d'évider les problèmes lors de la destruction de threads, il faut quitter le threads
convenablement, récupérer la mémoire allouée et obtenir les résultats du threads.
Si le threads ne doit pas communiquer de l'information à nouveau au thread principal de la
vcl, on n'a pas besoin de se préoccuper réllement de sa libération de mémoire. On utilise
FreeOnTerminate et le thread effectue lui-même sa propre désalocation de la mémoire.
Arrêt prématuré de thread
Il peut arriver qu'un thread doit en informer un autre qu'il va se terminer. Ceci se
produit généralement si un thread exécute une opération prolongé et que l'utilisateur
décide de quitter l'application ou que l'exécution doit être interrompue. TThread inclut
la méthode Terminate et la propriété Terminated pour supporter de telles situations. Lorsque
thread est démaré, sa propriété terminated est mise à false.C'est la responsabilité des
threads de vérifier périodiquement s'ils ont été terminés.En somme cette propriété signifié
terminait le thread le plus rapidement possible.
L'événement OnTerminate
Cet évènement survient lorsqu'un thread a fini d'être exécuté et non lorsque la méthode
Terminate est appelée. C'est très utile car on l'exécute comme le thread principal de la vcl.
C'est une façon très intéressante de ne pas avoir un thread vcl et de transférer ses donnés
à un thread de vcl. OnTerminate fonctionne étrangement à synchronise.
Grâce à du code trouvé sur le Web, j'ai créé une petite application qui peut exécuter
jusqu'à 3 threads en même temps. Ce programme vous permettra de mieux comprendre les notions
apprises sur les threads jusqu'à maintenant.
Code source disponible
ici
Blocage
Méthode de WaitFor
Il peut arriver qu'on est besoin que tous les autres thread soient terminés à un
certain moment lorsqu'on fait exécuter le thread de la vcl. voici un petit exemple pour
mieux comprendre ce que fait cette méthode.
Un thread A appelle la méthode WaitFor d'un thread B, le tread A est mis en attente
jusqu'à ce que le thread B est fini son exécution. Lorsque le thread A reprend, il est
certain que le résultat du thread B peut-être lu et que l'objet du thread représentant B
peut être détruit.
Il faut faire attention lorsqu'on utilise cette méthode, car elle ne peut pas recevoir de
message. Le formulaire ne pourra pas se redessiner, se redimensionner et communiquer
avec l'extérieur. En appelant PostMessage le problème sera moins visible, mais si le
traitement est vraiment long, il faudrait penser à ajouter un messager à l'usager. Il existe
de nombreuses techniques pour résoudre ce problème dont les messages d'attente de
win32.
Danger
Si on utilise synchronize et waitfor il est possible qu'il se produise un blocage de
notre application. Un blocage survient si les threads s'attendent les uns les autres de
façon cyclique. Un cercle vicieux en quelques sortes. Ce problème peut-être résout
en levant des exceptions. En utilisant pas synchronise et waitfor dans la même application,
on s'assure ainsi de ne pas rencontrer ce problème.
Thread: avancé
Inconvénient de synchronize
Synchronise a plusieurs inconvénients qui peuvent le rendre inacceptable pour des
applications multi-thread complexe.
- Utile lorsqu'on veut faire communiquer nos threads avec ceux de la vcl
- Si on utilise beaucoup de synchronize, la vcl bloque notre application
- Synchronize peut bloquer notre application si la vcl attend nos threads
Le thread principal de l'application devrait s'exécuter rapidement pour avoir un temps réponse optimal.
Il arrive très souvent que des threads communiquent avec la vcl dans le même sens. C'est
à dire lire un flux de donnés, exécuter une requête... Des données sont ainsi partagées. Il
faut alors s'assurer que seul un thread pourra modifier des donnés. La classe
TCriticalSection est une bonne solution.
Section critique
La classe TCriticalSection permet de bloquer l'accès à une partie du code à plusieurs
threads. Seul un thread pourra exécuter le code. La méthode Acquire empêche les autres
threads d'exécuter une section et Release enlève cette protection. L'api de Windows a bien
évidemment des fonctionnalités plus complètes.