IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Langage Delphi Discussion :

Threads: ça eut marché mais ça ne marche plus !


Sujet :

Langage Delphi

  1. #21
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 173
    Points
    4 173
    Par défaut
    On ne fait donc que reporter la gestion de la section critique dans le thread principal puisque Synchronize l'implémente déjà ! Et à l'arrivée, le thread secondaire sera bloqué la même chose puisque la gestion de l'affichage sera plus lente que notre boucle !
    Non pas du tout.
    Synchronize collecte les demandes d'exécution pour le thread principal, et les places dans une liste. La section critique que gère Synchronize sert à protéger la liste contre les accès concurrents.
    Synchronize positionnne un événement pour signaler au thread principal qu'il a des requêtes à traiter. Une fois l'événement signalé, Synchronize suspend le thread secondaire jusqu'à ce que sa demande ait été traitée. Le thread secondaire est ainsi complètement stoppé jusqu'à ce que le thread principal ait finit de tout redessiner.

    Dans la solution que je décris, le thread secondaire modifie des variables d'états et poste des messages au thread principal pour lui dire qu'il peut se mettre à jour.
    Le thread principal va lire ces variables.
    La section critique n'intervient que pour l'accès à ces variables, donc sur un temps très court. Le thread principal peut parfaitement se redessiner pendant que le thread secondaire continue son traitement.

    Le seul moment où il peut y avoir blocage, c'est si le thread principal veut lire les variables d'état exactement au même moment que le thread secondaire veut les modifier.
    Dans tous les autres cas, la section critique permettra de continuer l'exécution sans aucun blocage ni rallentissement. Ni d'un côté, ni de l'autre.

  2. #22
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 173
    Points
    4 173
    Par défaut
    Citation Envoyé par GoustiFruit Voir le message
    Admettons que je modifie la procédure SetCanCancel pour qu'elle ne contienne que "FCanCancel := Value;". Ensuite il faudrait donc attendre le prochain rafraîchissement (top timer) pour modifier le bouton "Annuler" en fonction de cette valeur ? Mais ça veut aussi dire que la valeur "Enabled" du bouton sera appliquée à chaque boucle du timer, soit chez moi 5 fois par seconde, alors que c'est une action qui n'aura peut-être besoin d'être faite qu'une fois tout au long du long traitement ?
    C'est une façon de faire. Mais on peut faire mieux : Tu poste simplement un message au thread principal pour que ce dernier le traite en désactivant le bouton...
    Pour ce qui est de définir plusieurs fois Bouton.Enabled := false, ça ne pose pas vraiment de problème. Comme tu ne modifies pas la valeur de la propriété, ça n'aura quasiment aucun effet. Le plus génant, c'est que tu attends 5s avant de désactiver le bouton. D'où l'intérêt de poster un message pour faire le traitement immédiatement.

  3. #23
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Donc dans mon SetCanCancel, je fais:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    FCanCancel := Value
    PostMessage(Self.Handle, WM_MY_MESSAGE, Integer(FCanCancel), 0);
    Et je récupère ce message dans la même fenêtre ? (mon ProgressDialog ?)

  4. #24
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 173
    Points
    4 173
    Par défaut
    Oui c'est l'idée.
    Tu récupère le message dans la fiche à laquelle tu l'as envoyé. Tu as fait le post à "Self.Handle" donc tu le récupères dans la fiche indiquée par Self.

    Ce serait cependant plus "beau" si tu donnais le handle de la fiche au thread secondaire (je veux dire par là, la classe qui implémente le thread secondaire) et que tu postais le message depuis la classe du thread secondaire. De cette façon, on voit bien que c'est le thread secondaire qui envoie le message, puis le thread principal qui le traite.
    Bien sûr à l'exécution ça ne change rien, mais je trouve ça plus lisible.

  5. #25
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Hum, j'ai déjà écrit un peu de code avant de voir ton message, le résultat est légèrement différent de ce que tu prônes... Au départ j'ai été embêté par le Handle parce qu'un composant non-visuel n'en possède pas; et ensuite parce qu'il fallait parfois accéder aux propriétés du composant et d'autres fois à celles du dialogue lui-même.
    Le code est ici avec un petit projet compilé: http://www.filedropper.com/progressdialog (je teste le service pour la première fois, je ne sais pas si ça va aller) et en gros je fais ça:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    procedure TSgProgressDlg.SetCanCancel(const Value: Boolean);
    begin
      FCanCancel := Value;
     
      PostMessage(FHWnd, WM_REFRESH_INFOS, 4, 0);
    end;
    Le PostMessage est reçu par:

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TSgProgressDlg.WndMethod(var Msg: TMessage);
    begin
      if Msg.Msg = WM_REFRESH_INFOS then
        UpdateDisplay(Self, Msg.WParam)
      else
        Msg.Result := DefWindowProc(FHWnd, Msg.Msg, Msg.WParam, Msg.LParam);
    end;
    Qui renvoie sur:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    procedure TSgProgressDlg.UpdateDisplay(Sender: TObject; ADisplay: Integer);
    begin
      if not Assigned(FProgressDlg) then
        Exit;
     
      with FProgressDlg do begin
        case ADisplay of
          0: begin
          end;
          { ... }
      end;
    end;
    Ouf !

  6. #26
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 753
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 753
    Points : 13 336
    Points
    13 336
    Par défaut
    Ok Franck, bien reçu

    Le thread secondaire notifie le principal d'une mise à jour disponible (Asynchrone par PostMessage). Lorsqu'il en a le temps et le besoin, ce dernier fait une copie locale (à usage exclusif du thread principal) des données le plus rapidement possible pour libérer la section critique le plus vite possible. L'affichage se faisant gentillement par la suite.

    Mais finalement, le section critique est-elle vraiment indispensable dans ce cas (celui à GoustiFruit) ? Il n'y a pas de dialogue, l'information est unidirectionnelle (du thread secondaire au principal) et la seule chose qui puisse arriver est que l'affichage ait un temps de retard.

  7. #27
    Membre éclairé Avatar de Kaféine
    Homme Profil pro
    Inscrit en
    Avril 2007
    Messages
    569
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Avril 2007
    Messages : 569
    Points : 736
    Points
    736
    Par défaut
    Citation Envoyé par Franck SORIANO
    Non pas du tout. Bien au contraire. Imagine une appli de type traitement de texte. Lorsque tu appuies sur une(...)
    en disant 1 processeur par tâche j'imaginais plutôt des traitements qui occupent le cpu pendant 100% du temps. 1 cpu par tache plutôt que 1 cpu pour n taches, normalement les taches sont executées en même temps sur la solution 1, alors que dans la solution 2, les n taches se partagent 1 cpu non?

    Citation Envoyé par Franck SORIANO
    C'est simple, le multi-tâche ne fonctionne tout simplement pas comme ça.
    Un thread possède la main sur le CPU et exécute son traitement. A un moment ou à un autre, il va devoir effectuer une E/S pour obtenir les informations nécessaires à son traitement.
    J'ai du mal...
    Ok, si le thread possède la main sur le CPU et execute son traitement alors dans le cas d'une boucle infini sans rien d'autre dans le traitement, par exemple 3 threads qui chacun execute une boucle infinie: D'accord mon CPU est à 100% mais c'est pas pour autant que je ne peux plus utiliser mon traitement de texte. Même si je tape du texte dans notepad mes boucles infinies continurons de tourner. si c'est pas gràce au systéme préemptif, c'est gràce à quoi alors?, le module de windows responsable de la préemption s'occupe d'interrompre les threads tour à tour pour passer au suivant! sinon mon ordinateur serais complétement gelé et je pourrais pas switcher vers d'autre application!?

    Bon je vais arrêter de polluer le topic de GoustiFruit.
    Finalement cette conversation m'a destabilisé :\
    Le point positif c'est qu'elle m'a donnée envie de lire sur le sujet afin de gommer toutes les eventuelles fausses idées que je me suis fait à propos du multitâche.

  8. #28
    Expert confirmé

    Profil pro
    Leader Technique
    Inscrit en
    Juin 2005
    Messages
    1 756
    Détails du profil
    Informations personnelles :
    Âge : 46
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Activité : Leader Technique
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juin 2005
    Messages : 1 756
    Points : 4 173
    Points
    4 173
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Mais finalement, le section critique est-elle vraiment indispensable dans ce cas (celui à GoustiFruit) ? Il n'y a pas de dialogue, l'information est unidirectionnelle (du thread secondaire au principal) et la seule chose qui puisse arriver est que l'affichage ait un temps de retard.
    Il faut voir en effet ce que GoustiFruit fait. Une section critique n'est pas nécessairement indispensable. Ca dépend des informations à partager entre les deux threads et des risques encouru.
    Le principal, c'est de ne pas manipuler de composants visuels de la VCL depuis le thread secondaire.

    Citation Envoyé par Kaféine Voir le message
    Ok, si le thread possède la main sur le CPU et execute son traitement alors dans le cas d'une boucle infini sans rien d'autre dans le traitement, par exemple 3 threads qui chacun execute une boucle infinie: D'accord mon CPU est à 100% mais c'est pas pour autant que je ne peux plus utiliser mon traitement de texte. Même si je tape du texte dans notepad mes boucles infinies continurons de tourner. si c'est pas gràce au systéme préemptif, c'est gràce à quoi alors?, le module de windows responsable de la préemption s'occupe d'interrompre les threads tour à tour pour passer au suivant! sinon mon ordinateur serais complétement gelé et je pourrais pas switcher vers d'autre application!?
    C'est bien ça. Je n'ai pas dit que le préemptif n'existait pas et qu'il n'y avait jamais de préemption. J'ai dit que le cas était plutôt rare. La préemption est une sécurité pour les cas où justement des threads entrent dans des boucles infinies ou qui durent trop longtemps.
    Ce que je dit, c'est que dans une application bien faite, ça arrive rarement (mis à part les applications de calculs numériques bien sûr).

  9. #29
    Membre à l'essai
    Inscrit en
    Juin 2005
    Messages
    16
    Détails du profil
    Informations forums :
    Inscription : Juin 2005
    Messages : 16
    Points : 13
    Points
    13
    Par défaut SendMessage / PostMessage
    Bonjour,

    Le thread principal qui gere toute la partie GUI ne peut pas etre appelee a partir d'un autre thread. Donc il faut trouver un moyen de communiquer les informations entre ton thread secondaire et ton thread principal. Les problemes de synchronization de thread lorsque la machine n'a qu'un CPU n'apparaisse que tres rarement. Avec un Multi-coeurs ce genre d'erreur est presque immediatement apparent.

    Une maniere simple est de faire:
    procedure Monthread.Execute;
    begin
    Ici on a un boucle / liste evenement
    de temps a temps on appelle une methode Avec Synchronize qui va suspendre ce thread, joindre le thread principal ce qui va te permettre d'afficher tes infos et revenir.
    end;

    C'est parfaitement acceptable la plupart du temps. L'interruption du thread secondaire avec synchronize est minime.

    Voila pour la methode simple.

    Une bien meilleure methode est d'utiliser la pompe a message de ton application et d'envoyer les messages de ton thread secondaire vers ton thread principal avec PostMessage ou SendMessage. L'un est synchrone, l'autre est asynchrone. Je ne sais plus lequel est lequel. Il faut utiliser celui qui est asynchrone pour du vrai multi-threading. Sinon autant utiliser Synchronize! Il faut faire attention a la gestion de la memoire et il faut savoir recevoir les messages windows mais cela n'est difficile que la premiere qu'on le fait...

    Enfin, si tu utilises COM/DCOM alors il y a d'autres choses a prendre en consideration mais je ne pense pas que cela soit ton cas.

  10. #30
    Membre éclairé
    Profil pro
    Inscrit en
    Octobre 2002
    Messages
    707
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2002
    Messages : 707
    Points : 777
    Points
    777
    Par défaut
    Bonjour drakken,

    Merci pour tes explications, je comprends maintenant pourquoi ça marchait sur mon ancienne machine single core et pas sur ma nouvelle, multi-cores !

    Pour le reste je pense que c'est ce à quoi je suis arrivé (si j'ai bien compris), le thread secondaire écrit les valeurs de quelques variables globales, et le thread principal les lit, à intervalles réguliers pour la barre de progression, et à la réception de messages (envoyés par PostMessage, l'asynchrone donc ?) pour les autres propriétés (ex: caption).

Discussions similaires

  1. Ordinateur marche mais ecran eteint
    Par bourvil dans le forum Périphériques
    Réponses: 18
    Dernier message: 19/12/2005, 09h02
  2. Code qui marche, mais pas la mise à jour
    Par Cablan dans le forum Access
    Réponses: 7
    Dernier message: 24/10/2005, 17h09
  3. Script qui marche mais pas elegant[newbie]
    Par billybob2006 dans le forum Langage
    Réponses: 4
    Dernier message: 21/10/2005, 12h25
  4. [PL/SQL] requete qui marche mais pas dans un cursor
    Par victor.ward dans le forum Langage SQL
    Réponses: 3
    Dernier message: 09/09/2005, 22h21
  5. [Servlet - MySQL] Ca marche mais message d'erreur quand même
    Par ShinJava dans le forum Servlets/JSP
    Réponses: 2
    Dernier message: 09/11/2004, 15h15

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo