EXEMPLES DE THREADS

Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 - 19 mai 2012 à 13:18
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 - 22 mai 2012 à 09:03
Cette discussion concerne un article du site. Pour la consulter dans son contexte d'origine, cliquez sur le lien ci-dessous.

https://codes-sources.commentcamarche.net/source/54309-exemples-de-threads

cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
22 mai 2012 à 09:03
Merci BluePerfect pour tes remarques.

Elles méritent d'être étudiées et expérimentées. Je vais être obligé de diviser le code car il semble que l'on soit limité en taille à 1Mo pour les sources.

Avec tout ce que vous me dites, j'ai de quoi faire quelques sources encore...

A+
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
21 mai 2012 à 22:16
rectification :
'<>' pas '='

while not(self.Terminated) and (Forms.Application.ComponentState <> Classes.csDestroying)
do .....;
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
21 mai 2012 à 22:14
NB :
en plus de vérifier Terminated, ton thread devrait aussi checker ComponentState (de la fiche ou de Application), et quitter si sa valeur csDestroying est positionnée :

while not(self.Terminated) and (Forms.Application.ComponentState=Classes.csDestroying)
do .....;

@+
blueperfect Messages postés 234 Date d'inscription mardi 13 novembre 2007 Statut Membre Dernière intervention 21 novembre 2013
21 mai 2012 à 22:11
Je prends le commentaire en cours de route :

Etant moi-même sur le problème, je ne m'attarde pas sur tes sources...

Ce que j'en relève, est cependant important :

D'abord Synchronize...
Tu peux l'éviter en gérant l'affichage d'une autre manière : avec le fameux TControlCanvas...
Tu lance un thread qui construit un TBitmap, et un autre qui toutes les 25ms utilise un TControlCanvas (et Lock/unlock) pour afficher ce TBitmap sur un control (qui peut être la fiche)... Plus de Invalidate, et pas de timer...plus de VCL intempestive...de plus, l'intérêt (le gain de vitesse) est surprenant lorsque les threads produisent eux-même des "sous-bitmap'...

Pour ton erreur de fin de traitement : le thread DOIT checker Terminated (comme le dit la doc), mais lorsque tu quitte l'application (ce qui ferme la fiche), le thread n'est pas "terminated", et devient instable... Installe un système de sémaphore (un simple pointeur sur un booléen) que tu renseigne à vrai en sortie de Execute, ou dans DoTerminate...Ne quitte ta fiche que lorsque le flag est positionné (par une boucle while not(thread.StopFlag^) do Sleep(1); )...

Si tu comptes stocker et échanger des variables entre threads (des structures, des chaines, des variants...), regarde mon objet TVariables... Tout l'intérêt réside dans l'utilisation d'une TThreadList pour stocker les Variants...

@+
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
21 mai 2012 à 08:39
Yo Manchester,
Heu si j'ai bien compris, d'après toi je dois inclure une gestion de la mémoire du Thread? Je pensai que c'était transparent... Bon je suis en train de réfléchir à la récriture du projet 3, je vais tester ta proposition.

C'est bizarre, je viens de déplacer simplement les threads dans une autre unité et je ne plus écrire if MonThread.Terminated dans ma fiche principale. Je me contente donc du simple if Assigned(MonThread) then MyThread.Terminate;

Quant à ta remarque sur la durée du fonctionnement du Thread, c'est une idée que je pourrai exploiter tout simplement pour gérer la durée du clignotement de la LED.

Merci
cs_ManChesTer Messages postés 374 Date d'inscription vendredi 20 octobre 2000 Statut Modérateur Dernière intervention 15 janvier 2021
21 mai 2012 à 02:13
Hmm décidement...

Le strpcopy vers le buffer évidement,

Bon Coding...

ManChesTer.
cs_ManChesTer Messages postés 374 Date d'inscription vendredi 20 octobre 2000 Statut Modérateur Dernière intervention 15 janvier 2021
21 mai 2012 à 02:11
Heuu il faut lire :
sec:=0;
repeat
Sleep(1000);
strpcopy("Je tourne depuis "+inttostr(sec)+' Secondes");
inc(sec)
Resultat:=True;
until Terminated;

Bon Coding...

ManChesTer.
cs_ManChesTer Messages postés 374 Date d'inscription vendredi 20 octobre 2000 Statut Modérateur Dernière intervention 15 janvier 2021
21 mai 2012 à 02:08
Salut,

Une petite astuce qui fonctionne:

type
MyThread = class(TThread)
public
constructor Create(CreateSuspended:boolean);
destructor Destroy; override;
ResultAdress:Longint;
Resultat:Boolean;
protected
procedure Execute; override;
end;

constructor MyThread.Create(CreateSuspended:boolean);
begin
inherited Create(CreateSuspended);
FreeOnTerminate:=false;
Getmem(Mathread.ResultAdress,unbuffersize)
...
end;

destructor TPersoThread.Destroy;
begin
resultat:=false;
freemem(Mathread.ResultAdress);
inherited;
end;

procedure MyThread.Execute;
var sec : longint64;
begin
repeat
Sleep(100);
strpcopy("Je tourne depuis "+inttostr(sec)+' Secondes");
Resultat:=True;
until Terminated;
end;

Procedure Tform1.LireDonees_MyThread; // depuis un ttimer par ex...
Begin
If Mythread.Resultat then
begin
Form1.Caption:=Strpas(MyThread.ResultAdress);
Mythread.Resultat:=false;
end;
end;

on peut aussi complexifié en utilisant par exemple des record ou autres...
l'usage de ReallocMem & co est permis mais ! aux synchros.
En bref ca évite d'utiliser les disques ou les msg intempestifs.

Bon Coding...

ManChesTer.
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
20 mai 2012 à 10:15
En fait, je vais faire une MAJ du projet 3 pour plus de lisibilité et essayer de régler quelques bugs!
Yo les delphistes!
cs_Jean_Jean Messages postés 615 Date d'inscription dimanche 13 août 2006 Statut Membre Dernière intervention 13 décembre 2018 3
19 mai 2012 à 14:22
Salut Bactérius,

Merci pour tes commentaires très pertinents. Je suis d'accord avec toi pour presque tout. Me passer de la méthode synchronize serait un rêve, mais il ne faudrait pas que ça alourdisse de trop le code.

En fait j'ai écris ce code assez rapidement et ne voulais pas en faire une usine à gaz. C'est loupé! J'ai presque passé plus de temps sur le Pdf pour expliquer ce que je voulais faire. Le code se compliquait au fur et à mesure de mes essais.

Le prochain projet (j'ai encore plein de choses à expérimenter) tiendra compte de simplifications sur l'organisations en unités séparées. Bien sûr j'essaierai de tenir compte de tes remarques...

A+
Bacterius Messages postés 3792 Date d'inscription samedi 22 décembre 2007 Statut Membre Dernière intervention 3 juin 2016 10
19 mai 2012 à 13:18
Bonjour, ben je passais par ici et j'ai remarqué ta source! C'est beaucoup de boulot et je trouve ca très bien de faire des petits projets pour se familiariser avec différents concepts (et surtout le faire d'une manière organisée, particulièrement avec un PDF, chapeau!). Je suis moi-meme très interessé dans le calcul haute performance, donc faire fonctionner un modèle multi-threads efficacement est une des mes activités.

Quant au problème de l'erreur quand l'application se ferme, il faut faire attention que le thread ne soit pas en train d'executer du code VCL lorsque la fiche est détruite, sinon il lancera une violation d'accès. Il est en general utile de séparer les données utilisées par les differents threads dans une unité completement dissociée du code VCL (fiche, etc...). Idéalement un thread devrait pouvoir continuer a fonctionner sans fiche principale (sans l'affichage du progrès et autres, evidemment). En fait c'est le principe par lequel beaucoup d'applications utilitaires fonctionnent, ils lancent les threads "travailleurs" qui font leur boulot, et l'affichage de l'interface graphique est un choix qui est fait par l'utilisateur (par ligne de commande ou autre), les résultats des threads étant de toute facon écrits sur disque. Parfois chaque thread a sa propre fiche, mais je suis pas trop fan de ca.

Note qu'il est aussi possible de complètement contourner les appels a Synchronize et d'envoyer des messages Windows a la fiche principale a la place, ca peut parfois simplifier les choses (mais pas toujours!). Ca évite aussi naturellement le probleme de violation d'accès puisqu'au lieu d'essayer d'accéder a la fiche principale, il ne fera qu'envoyer un message a une fiche qui n'existe plus (ce qui ne produit aucune erreur).

Juste une remarque, il faudrait separer les threads et les petites procédures d'utilité dans des unités séparées ... c'est assez dur a lire en ce moment.

C'est tout pour le moment, c'est beaucoup de code et j'ai pas encore tout lu!
Rejoignez-nous