Les Threads et les composants VCL

Résolu
Toya78 Messages postés 44 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 août 2008 - 22 janv. 2008 à 20:37
cs_darkcodersc Messages postés 7 Date d'inscription lundi 17 mars 2008 Statut Membre Dernière intervention 20 novembre 2009 - 20 nov. 2009 à 09:41
Bonjour à tous !

Je me penché depuis peu sur les Threads (en lisant le super tutoriel de grandvizir que je remercie au passage :)).

J'ai toutefois un petit problème que je ne parviens pas à éclaircir tout seul (bien qu'ayant fait des recherches sur le sujet).

Voici ma situation : j'ai créé un Thread qui réalise un gros traitement. A la fin de ce traitement, un TBitmap est généré et est copié dans un TImage. Parfois j'ai un plantage (aléatoire) 'Descripteur non valide' sur mon TBitmap en cours de création.
Je précise que mon Threads n'appelle pas le traitement en Synchronize (sinon ma form n'est plus rafraîchie...).

procedure TMonThread.Execute;
begin
MonTraitement; // <= gros traitement
Generation_du_bitmap; // <= erreur parfois si appellée sans Synchronize
//Synchronize(Generation_du_bitmap); // <= aucune erreur
end;


J'ai lu que lorsqu'un Thread touche aux composants VCL il faut utiliser Synchronize.

Ma question est la suivante : est-ce vraiment le problème que je rencontre (ça ne plante pas lors du Assign dans mon TImage, mais avant : lors de la génération pure et dure du TBitmap) ?

En passant en Synchronize la partie "génération du TBitmap" je n'ai plus aucun problème. Par contre je me demande pourquoi je n'ai pas de plantage lors de mon traitement vu que celui-ci met à jour une ProgressBar (qui est un composant VCL...).

Je vous avoue que je suis perdu dans tout ça :)

Quelqu'un peut-il me montrer la lumière ? O:-)

7 réponses

Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
24 janv. 2008 à 19:56
Oui, tous les composants, même un TLabel ! 
Imagine que ton Thread principal change le contenu d'un TLabel en même temps qu'un Thread secondaire... Au mieux tu auras un résultat inattendu, au pire un plantage.

La commutation de tâche du processeur ne se préoccupe absolument pas des procedures Delphi. Derrière chaque procédure il y a  toute une série d'instructions en code machine qui peut être interrompue à tout moment. Si 2 Threads peuvent modifier une même variable, rien ne garantie la cohérence de celle-ci.

exemple:



if A = 0 then A := 1;
B := B/A;

Si 2 Threads ont accès à A, il est tout-à-fait possible que A soit remis à zéro après le test et alors...

Il est donc primordial  de s'assurer que les différents Threads d'un process travaillent avec des données séparées. Ou alors,  il faut utiliser des mécanisme de synchronisation comme Synchronize.
Il y a aussi les sections critiques qui sont utiles pour, par exemple, synchroniser 2 Threads secondaires, mais qui sont aussi applicables au Thread principal. (regarde TCriticalsection dans l'aide).

Voilà, j'espère que tu y vois un peu plus clair. En fait, ce n'est pas compliqué mais ça demande beaucoup d'attention.
3
f0xi Messages postés 4205 Date d'inscription samedi 16 octobre 2004 Statut Modérateur Dernière intervention 12 mars 2022 35
22 janv. 2008 à 20:55
je vais peut etre dire une betise mais il me semble que lors de l'utilisation de thread, les variables propre aux thread doivent etre declaré dans Threadvar et non dans var.

au cas ou tu fait :

var
  BMP : TBitmap;

il faudrait tester :

threadvar
  BMP : TBitmap;

cela empechera peut etre ceraines erreurs.
<hr size="2" width="100%" />
http://deefaze.gnomz.com
0
Toya78 Messages postés 44 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 août 2008
22 janv. 2008 à 21:03
Heu hé bien mon Thread possède une méthode Execute (normal jusque là...) qui appelle d'autres procédures qui génère mon TBitmap. Ainsi, mon TBitmap est déclaré dans ces procédures (en "var" donc)... Mais c'est intéressant ce "threadvar" je ne l'avais jamais vu. Je vais me renseigner ça peut toujours servir. Merci pour cette info f0xi.

PS :  au cas où, je vais quand même essayer de regrouper toutes mes procédures dans mon Execute pour déclarer mon TBitmap en "threadvar", on sait jamais ça coûte rien d'essayer :)
0
Caribensila Messages postés 2527 Date d'inscription jeudi 15 janvier 2004 Statut Membre Dernière intervention 16 octobre 2019 18
24 janv. 2008 à 14:05
Salut,

Le noyau Win32 utilise un mécanisme de stockage local aux threads qui permet de créer plusieurs copies des variables globales, une par thread. Delphi réutilise ce mécanisme via la clause ThreadVar.
Cependant il est environ 10 fois plus rapide d'accéder à un champ d'objet plutôt qu'à une variable ThreadVar. La technique de stockage de ressource locale est donc à privilégier, style:



type
  TMonThread = class(TThread)
  private
    fLocalBtm : TBitmap; // 

<-- Variable stockée dans l'objet TThread.
    ....





Cela dit, les variables qui peuvent exister uniquement pendant la durée d'exécution d'une routine doivent être stockées sous forme de variable locales, car leur accès est encore plus rapide que celui à un champ de l'objet TThread.

D'autre part, si tu dois mettre à jour un composant VCL, tu dois utiliser Synchronize. Sinon, ça ne plantera certainement pas à chaque fois, mais il y aura tj un risque. Et même 1 fois sur 1 million, c'est pas acceptable.
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
Toya78 Messages postés 44 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 août 2008
24 janv. 2008 à 19:05
Hello Caribensila,

En effet même un plantage sur 1 million n'est pas tolérable.

J'ai fait quelques tests et il semblerait qu'en effet les Threads n'aiment pas les composants VCL surtout s'ils (les composants) utilisent des TBitmap (ce qui est le cas de ma ProgressBar, qui, je le signale au passage, n'est pas une TProgressBar, mais un composant dérivé qui utilise des TBitmap).

Par contre lorsque tu dis "si tu dois mettre à jour un composant VCL, tu dois utiliser Synchronize", absolument TOUS les composants VCL sont cercernés sans exception ?
Par exemple, mettre à jour le Caption de ma Form, ou le Caption d'un TButton entraîne-t-il aussi l'utilisation de Synchronize ? Étant donné que ces composants sont assez simplistes je me demandais s'ils étaient concernés.
0
Toya78 Messages postés 44 Date d'inscription vendredi 1 septembre 2006 Statut Membre Dernière intervention 23 août 2008
24 janv. 2008 à 20:07
Ok très bien :)
Je passerai tout ce qui touche les composants en Synchronize alors.
Et dire que j'ai passé des heures à vérifier/modifier mon code car je pensais à une fuite de mémoire avec mes TBitmap... :')

Merci encore pour votre aide !
0
cs_darkcodersc Messages postés 7 Date d'inscription lundi 17 mars 2008 Statut Membre Dernière intervention 20 novembre 2009
20 nov. 2009 à 09:41
Sa c'est pour les threads VCL mais comment syncrhoniZ un composant VCL avec les thread Win32?
Merci,
0
Rejoignez-nous