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

C++Builder Discussion :

Quelques questions sur les threads


Sujet :

C++Builder

  1. #1
    Membre régulier Avatar de benj63
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Mai 2002
    Messages
    207
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 207
    Points : 99
    Points
    99
    Par défaut Quelques questions sur les threads
    Bonjour,

    Suite à ce sujet, je me suis penché sur les threads. Comme j'ai de nombreuses questions à propos de l'objet TThread de C++ Builder 6, je me permets de créer un sujet à part afin de poser mes diverses questions. J'ai cherché dans la FAQ, j'ai lu le tutoriel sur les threads et l'aide de C++ Builder mais je n'ai pas trouvé de réponses...

    Au final, je souhaiterais réaliser un objet contenant un TTimer et un TThread, qui exécuterait une fonction à une heure donnée. J'ai commencé le développement de l'objet, le TTimer fonctionne, et à une heure donnée, il est prêt à exécuter ce que je souhaite.

    Voici mes questions :

    - peut-on choisir le moment de l'exécution d'un thread ? la méthode Execute doit être private donc on ne peut pas le lancer quand on le souhaite... J'ai remarqué que lors de la création d'une instance de TThread avec new, celui-ci était lancé à la FIN de la fonction ayant créé cette instance (voir le code exemple + bas). On peut le créer en le mettant par défaut en mode "suspendu", et faire un "resume" dès qu'on souhaite le lancer, mais dans ce cas... on ne peut le lancer qu'une fois !

    - où mettre les appels au destructeur du thread "delete MonThread1" ? On ne peut pas le mettre après le new, sinon le thread est détruit avant même d'avoir été lancé... Faut-il utiliser FreeOnTerminate ? Cela correspond-t'il à sa destruction comme un delete à la fin de son exécution ?

    - pour l'objet que je veux créer, comme un thread semble nécessairement être démarré avec un new, peut être faut-il que j'envoie à mon objet l'adresse de la fonction à exécuter, et non l'adresse d'un thread en le laissant suspend() lors de l'initialisation de l'objet ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    class TimerPlanning : public TTimer
    {
      private:
            void __fastcall VerifierTimer(TObject *);
     
      public:
            TThread *Thread;
     
            unsigned short PlanningHeure;   
            unsigned short PlanningMinute;  
     
           __fastcall TimerPlanning(TComponent *AOwner, unsigned short planning_heure, unsigned short planning_minute, TThread *thread);
    };


    J'ai également mis en place un programme pour tester les threads, et notamment le fait qu'il se lance A LA FIN de la fonction dans laquelle ils sont appelés :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    //---------------------------------------------------------------------------
    // 1er thread
    //---------------------------------------------------------------------------
    __fastcall TMonThread1::TMonThread1(bool CreateSuspended)
            : TThread(CreateSuspended)
    {
    }
     
    void __fastcall TMonThread1::Execute()
    {
    for(int i=0;i<500;i++)
    {
            Form1->Label1->Caption = String(i);
            Sleep(10);
            Application->ProcessMessages();
    }
    }
     
    //---------------------------------------------------------------------------
    // 2ème thread
    //---------------------------------------------------------------------------
    __fastcall TMonThread2::TMonThread2(bool CreateSuspended)
            : TThread(CreateSuspended)
    {
    }
     
    void __fastcall TMonThread2::Execute()
    {
    for(int i=0;i<500;i++)
    {
            Form1->Label2->Caption = String(i);
            Sleep(10);
            Application->ProcessMessages();
    }
    }
     
    //---------------------------------------------------------------------------
    // Bouton pour lancer le 1er thread
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button1Click(TObject *Sender)
    {
    TMonThread1 *MonThread = new TMonThread1(false);
    }
     
    //---------------------------------------------------------------------------
    // Bouton pour lancer le 2ème thread
    //---------------------------------------------------------------------------
    void __fastcall TForm1::Button2Click(TObject *Sender)
    {
    TMonThread2 *MonThread = new TMonThread2(false);
    Sleep(3000);
    }
    Ici, si j'appuie sur Button1, mon 1er thread se lance bien. Par contre, quand j'appuie sur Button2, à cause du "Sleep(3000)", le 2ème thread ne se lance pas juste après le new, le 1er thread est bloqué pendant les 3000 ms, puis les 2 threads sont relancés. Qu'est-ce qui se passe ?? Je pensais que dès que l'on faisait un new thread, celui-ci était exécuté ! Il ne s'exécute alors qu'APRES la FIN de la fonction qui l'a lancée ? C'est bizarre, non ? J'ai essayé avec un Application->ProcessMessages(); juste après le new, ça ne change rien...

    Je sais que le Sleep(3000) est un événement bloquant. Mais si je mets par exemple à la place Form1->Label2->Caption = "fini", "fini" apparaît juste avant le lancement du thread... puisque la fonction Button2Click est executée entièrement avec son lancement... bizarre, alors que dans le code l'affichage de "fini" est après le thread !

    Auriez-vous des idées pour ces questions et problèmes ? Evidemment, si vous ne pouvez pas répondre à toutes mes questions, je souhaite bien quelques explications sur les points que vous connaissez...

    Si je ne suis pas clair, merci de me le faire savoir, j'essaierai de corriger mon message rapidement, car c'est assez urgent...

    En vous remerciant par avance.

  2. #2
    Rédacteur
    Avatar de Greybird
    Inscrit en
    Juin 2002
    Messages
    673
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 673
    Points : 1 271
    Points
    1 271
    Par défaut
    Bonjour,

    Je ne suis pas spécialiste des threads, mais l'accès à des objets de la VCL dans un thread doit se faire dans un bloc synchronisé, ce qui n'est pas le cas ici, il me semble ?

    Cordialement,

    Arnaud

  3. #3
    Membre régulier Avatar de benj63
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Mai 2002
    Messages
    207
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 207
    Points : 99
    Points
    99
    Par défaut
    Je ne souhaite pas particulièrement que les différents threads soient synchronisés entre eux... Je souhaite juste pouvoir exécuter plusieurs fonctions simultanément et indépendamment, à heures fixes grâce à mon objet TimerPlanning. Voilà pourquoi je n'ai pas mis de synchronize.

  4. #4
    Membre éprouvé Avatar de Caine
    Inscrit en
    Mai 2004
    Messages
    1 028
    Détails du profil
    Informations personnelles :
    Âge : 52

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 028
    Points : 1 122
    Points
    1 122
    Par défaut
    Tu peux créer le Thread suspendu et le réveiller à partir de son ID dans un autre thread (le principal par exemple).

    Tu peux aussi utiliser des Events:

    Quand ton Timer souhaite réveiller le Thread, il émet un évènement particulier.

    Ton thread commence sa boucle de traitement par un WaitForSingleObject sur l'ID de cet Event. Il sera donc lancé uniquement quand l'Event est signalé.

    Pour la destruction du Thread, met la dans l'évènement OnDestroy de ton application principale. En effet, si l'application se termine, les threads peuvent être détruits.

    Voilà, j'espère t'avoir aiguiller.

  5. #5
    Membre éprouvé

    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    1 163
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 163
    Points : 1 148
    Points
    1 148
    Par défaut
    Citation Envoyé par Caine
    Tu peux créer le Thread suspendu et le réveiller à partir de son ID dans un autre thread (le principal par exemple).
    Ou alors tout simplemant dans le OnTimer de ton TTimer appeler la fonction Resume de ton TThread.

  6. #6
    Membre régulier Avatar de benj63
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Mai 2002
    Messages
    207
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 207
    Points : 99
    Points
    99
    Par défaut
    Merci pour ces réponses

    Le problème, c'est que je ne pourrai lancer le thread qu'une fois dans ce cas... Après le resume, le thread passera en état "Terminated" et j'aurais beau refaire des Resume() ultérieurs, la fonction ne se lancera plus !

    Alors que je souhaite que le OnTimer puisse se déclencher plusieurs fois par jour... et tous les jours !

    Pour la suppression du thread, vaut-il mieux dans tous les cas que je passe par un FreeOnTerminate ?

  7. #7
    Membre éprouvé

    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    1 163
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 163
    Points : 1 148
    Points
    1 148
    Par défaut
    Tu mets une boucle dans ton thread...de sorte qu'il fasse ton traitement en boucle sauf quand on lui demande de se terminer.
    A la fin du traitement du met un Suspend pour qu'il attende le prochain appel à Resume.

    En gros ça donne ça pour ta fonction Execute de ton TThread :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
    while( !Terminate )
    {
        // Fait ce que tu as à faire
        Suspend();
    }
    Le seul inconvénient c'est que si tu veux détruire le thread et que ton timer met du temps à se déclencher il faudra dans le pire des cas que tu attendes l'intervale de ton timer pour que ton thread soit détruit.

  8. #8
    Membre éprouvé Avatar de Caine
    Inscrit en
    Mai 2004
    Messages
    1 028
    Détails du profil
    Informations personnelles :
    Âge : 52

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 028
    Points : 1 122
    Points
    1 122
    Par défaut
    La méthode exécute d'un thread est toujours une attente par boucle de la condition Terminated = TRUE.

    Donc, tu pourras, si tu écris correctement la méthode exécute, suspendre et lancer ton thread autant de fois que tu le veux.

  9. #9
    Membre régulier Avatar de benj63
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Mai 2002
    Messages
    207
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 207
    Points : 99
    Points
    99
    Par défaut
    Je vous remercie pour ces méthodes... Je vais essayer d'en tirer parti pour réaliser ma classe PlanningTimer.

    Je ne ferme pas encore le topik par un [résolu], si d'autres personnes avaient d'autres réponses à mes questions sur les threads, je serais toujours preneur !

  10. #10
    Rédacteur
    Avatar de Greybird
    Inscrit en
    Juin 2002
    Messages
    673
    Détails du profil
    Informations forums :
    Inscription : Juin 2002
    Messages : 673
    Points : 1 271
    Points
    1 271
    Par défaut
    Citation Envoyé par benj63
    Je ne souhaite pas particulièrement que les différents threads soient synchronisés entre eux... Je souhaite juste pouvoir exécuter plusieurs fonctions simultanément et indépendamment, à heures fixes grâce à mon objet TimerPlanning. Voilà pourquoi je n'ai pas mis de synchronize.
    J'ai du mal m'exprimer. Le fait que l'accès à la VCL soit synchronisé n'est pas une option, mais une obligation.

  11. #11
    Membre éprouvé

    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    1 163
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 163
    Points : 1 148
    Points
    1 148
    Par défaut
    Regarde l'aide de synchronize tu comprendras mieux pourquoi c'est obligatoire. Je suis moi aussi de me dépatouiller avec les Thread, en aucun cas Synchronize ne synchronise les Thread...

  12. #12
    Membre éprouvé Avatar de Caine
    Inscrit en
    Mai 2004
    Messages
    1 028
    Détails du profil
    Informations personnelles :
    Âge : 52

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 028
    Points : 1 122
    Points
    1 122
    Par défaut
    Synchronize va synchroniser deux Threads uniquement s'ils tapent tout les deux dans un même intervalle de temps à une ressource (VCL ou objets non graphiques).

    C'est le même mécanisme de synchronisation que par Mutex, section critique et Lecteur/Rédacteurs.

    En effet, si deux threads demandent un changement d'état d'un composant en même temps, que se passe-t-il? Ou, dans un cas plus frappant, si deux threads demandent à détruire un composant?

  13. #13
    Membre régulier Avatar de benj63
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Mai 2002
    Messages
    207
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 207
    Points : 99
    Points
    99
    Par défaut
    donc si je fais un appel à Button1->... ou Form1->Label1->... dans un thread, il faut que je fasse un synchronize() derrière ?

  14. #14
    Membre éprouvé Avatar de Caine
    Inscrit en
    Mai 2004
    Messages
    1 028
    Détails du profil
    Informations personnelles :
    Âge : 52

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 028
    Points : 1 122
    Points
    1 122
    Par défaut
    Et oui.
    C'est le plus sûr, sinon, sans raison, un jour le programme risque de planter.

  15. #15
    Membre régulier Avatar de benj63
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Mai 2002
    Messages
    207
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 207
    Points : 99
    Points
    99
    Par défaut
    D'accord, j'utiliserai Synchronize() à chaque fois que cela me semblera nécessaire.

    Je reste actuellement bloqué sur un bug bizarre : il n'est pas possible de faire un objet qui hérite d'un objet qui hérite d'un thread ?

    Je m'explique :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    // 1er thread qui hérite de TThred
    class TThread1 : public TThread
    {
       protected:
            void __fastcall Execute()
            {
                    // une fonction à lancer...
            }
     
       public:
            Config *VilleConfig;
     
            __fastcall TThread1(bool CreateSuspended, Config *config) : TThread(CreateSuspended)
            {
                    VilleConfig = config;
            }
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    // 2ème thread, qui hérite de TThread1
    class TThread2 : public TThread1
    {
       protected:
            void __fastcall Execute()
            {
                    // une fonction à lancer...
            }
     
       public:
            __fastcall TThread2 (bool CreateSuspended, Config *config) : TThread1(CreateSuspended, config)
            {
            }
    };
    et bien si je fais :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    TThread1 *test1 = new TThread1(true,maConfig);
    test1->Resume();
    ça fonctionne (le Execute de TThread1 est lancé)

    mais si je fais
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    TThread2 *test2 = new TThread2(true,maConfig);
    test2->Resume();
    le Resume ne lance jamais l'Execute du TThread2 !
    je ne vois pas où peut se situer le problème ?!!

  16. #16
    Membre éprouvé Avatar de Caine
    Inscrit en
    Mai 2004
    Messages
    1 028
    Détails du profil
    Informations personnelles :
    Âge : 52

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 028
    Points : 1 122
    Points
    1 122
    Par défaut
    Dans ton code, il n'y a aucune raison qu'il lance l'exécution de Thread2.

    Regarde bien le constructeur de Thread1, il fait appel au constructeur de TThread qui se charge de lancer Execute().

    Dans Thread2 tu appelles le constructeur de Thread1 => Execute() de Thread1 lancé. Mais à aucune moment tu ne t'occupes de l'Execute de Thread2.

    Je ne suis pas sûr d'avoir été clair.

  17. #17
    Membre régulier Avatar de benj63
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Mai 2002
    Messages
    207
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 207
    Points : 99
    Points
    99
    Par défaut
    Je crois que je te suis, mais dans ce cas, comment se fait-il que si je supprime Thread2 et que je fais :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    Thread1 *test = new Thread1(true, maConfig);
    test->Resume();
    le execute de Thread1 soit lancé ?!

  18. #18
    Membre éprouvé

    Profil pro
    Inscrit en
    Octobre 2003
    Messages
    1 163
    Détails du profil
    Informations personnelles :
    Âge : 39
    Localisation : France

    Informations forums :
    Inscription : Octobre 2003
    Messages : 1 163
    Points : 1 148
    Points
    1 148
    Par défaut
    Je ne comprend pas ta question, tu crée bien un TThread1 c'est donc normal que tu appelles l'Execute du TThread1.

    Cet appel est fait automatiquement par le constructeur de la classe TThread or pour ton constructeur TThread2, celui-ci commence par faire appel au constructeur de TThread1 qui fait directement appel à celui de TThread....qui va appeler la fonction Execute de TThread1.

    J'espère que c'est assez clair, pas facil d'exprimer cela clairement :S

  19. #19
    Membre régulier Avatar de benj63
    Homme Profil pro
    Responsable de service informatique
    Inscrit en
    Mai 2002
    Messages
    207
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Puy de Dôme (Auvergne)

    Informations professionnelles :
    Activité : Responsable de service informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Mai 2002
    Messages : 207
    Points : 99
    Points
    99
    Par défaut
    Ok, je comprends mieux, désolé d'être un peu long à la détente... Et si je déclare TThread1 sans mettre de fonction Execute() dedans, ça ne changera rien j'imagine ? Jamais la fonction Execute() de Thread2 ne sera lancée ?

  20. #20
    Membre éprouvé Avatar de Caine
    Inscrit en
    Mai 2004
    Messages
    1 028
    Détails du profil
    Informations personnelles :
    Âge : 52

    Informations forums :
    Inscription : Mai 2004
    Messages : 1 028
    Points : 1 122
    Points
    1 122
    Par défaut
    Tu as un problème de compréhension avec l'héritage je pense;
    Sans vouloir te vexer.

    Si tu veux créer un objet qui lance deux Thread, il te suffit de lui donner deux attributs de type TThread:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
     
    class MyDouble {
    private:
       TTHread *pThread1;
       TThread *pThread2;
    public
       MyDouble(bool CreateSuspended, Config *config);
    };
     
    MyDouble::MyDouble(bool CreateSuspended, Config *config) {
       pThread1 = new TThread(CreateSuspended,config);
       pThread2 =new TThread(CreateSuspended,config);
      ...
    }
    Avec l'héritage tu ne résoudras pas ton problème. L'héritage ne sert pas à empiler les constructeurs. Chaque classe enfant appelle le constructeur de la classe parent.

    Tu auras beau dériver N fois de TThread, tu ne pourras appeler qu'une seule fois le constructeur de TThread, il n'y aura jamais qu'un seul Thread dans l'application.

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Quelques question sur les threads
    Par Zoners dans le forum Concurrence et multi-thread
    Réponses: 8
    Dernier message: 15/04/2010, 22h19
  2. Quelques questions sur les annuaires ldap
    Par rvfranck dans le forum Réseau
    Réponses: 7
    Dernier message: 15/08/2006, 02h41
  3. Quelques questions sur les LOB
    Par Wurlitzer dans le forum Oracle
    Réponses: 2
    Dernier message: 14/06/2006, 17h32
  4. Question sur les threads
    Par Linio dans le forum Concurrence et multi-thread
    Réponses: 10
    Dernier message: 21/10/2005, 09h08
  5. Question sur les threads
    Par nicolas66 dans le forum MFC
    Réponses: 4
    Dernier message: 03/06/2005, 20h57

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