Les Threads et les composants VCL [Résolu]

Toya78 49 Messages postés vendredi 1 septembre 2006Date d'inscription 23 août 2008 Dernière intervention - 22 janv. 2008 à 20:37 - Dernière réponse : cs_darkcodersc 7 Messages postés lundi 17 mars 2008Date d'inscription 20 novembre 2009 Dernière intervention
- 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:-)
Afficher la suite 

Votre réponse

7 réponses

Caribensila 2674 Messages postés jeudi 15 janvier 2004Date d'inscription 11 mai 2018 Dernière intervention - 24 janv. 2008 à 19:56
+3
Utile
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.
Cette réponse vous a-t-elle aidé ?  
Commenter la réponse de Caribensila
f0xi 4304 Messages postés samedi 16 octobre 2004Date d'inscription 9 mars 2018 Dernière intervention - 22 janv. 2008 à 20:55
0
Utile
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
Commenter la réponse de f0xi
Toya78 49 Messages postés vendredi 1 septembre 2006Date d'inscription 23 août 2008 Dernière intervention - 22 janv. 2008 à 21:03
0
Utile
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 :)
Commenter la réponse de Toya78
Caribensila 2674 Messages postés jeudi 15 janvier 2004Date d'inscription 11 mai 2018 Dernière intervention - 24 janv. 2008 à 14:05
0
Utile
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.
Commenter la réponse de Caribensila
Toya78 49 Messages postés vendredi 1 septembre 2006Date d'inscription 23 août 2008 Dernière intervention - 24 janv. 2008 à 19:05
0
Utile
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.
Commenter la réponse de Toya78
Toya78 49 Messages postés vendredi 1 septembre 2006Date d'inscription 23 août 2008 Dernière intervention - 24 janv. 2008 à 20:07
0
Utile
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 !
Commenter la réponse de Toya78
cs_darkcodersc 7 Messages postés lundi 17 mars 2008Date d'inscription 20 novembre 2009 Dernière intervention - 20 nov. 2009 à 09:41
0
Utile
Sa c'est pour les threads VCL mais comment syncrhoniZ un composant VCL avec les thread Win32?
Merci,
Commenter la réponse de cs_darkcodersc

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.