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++ Discussion :

Sortir d'un while qui n'est pas dans la fonction


Sujet :

C++

  1. #1
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut Sortir d'un while qui n'est pas dans la fonction
    Bonjour, supposons un GUI avec une classe Menu.
    Cette classe Menu serais comme ci-dessous :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    class Menu
    {
        private :
            std::vector<Objet*> sous_objets;
            std::vector<Evenement> evenements;
            //Ceci est un exemple simplifier et donc on ne marquera pas tout.
        public :
            void GUI_Main();
            void exit_Menu();
            //Ceci est un exemple simplifier et donc on ne marquera pas tout.
    };
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    void Menu::GUI_Main()//équivalent de GTK_main() par exemple
    {
        unsigned int i;
        while(1)
        {
            SDL_Delay(10);
            for(i=0;i<evenements.size();i++)
                evenements[i](this);
        }
    }
    Supposons, que l'on souhaite faire la fonction exit_Menu qui serait appelée depuis un des foncteurs Evenement.
    Comment la programmer ?
    L'objectif serait de faire l'équivalent de :
    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
     
    void Menu::GUI_Main()
    {
        unsigned int i;
        while(1)
        {
            SDL_Delay(10);
            for(i=0;i<evenements.size();i++)
                evenements[i](this);
        }
        end;
    }
     
    void Menu::exit_Menu()
    {
        goto end;
    }
    Quelqu'un a t-il une solution ? (Autre chose que se débrouiller pour tester la valeur de retour de evenement (qui renverait un bool))

    Ce code n'ayant pas été compilé, il se peut qu'il y ai des erreurs qui ne nous interessent pas : l'important étant la conception.

  2. #2
    Rédacteur

    Avatar de ram-0000
    Homme Profil pro
    Consultant en sécurité
    Inscrit en
    Mai 2007
    Messages
    11 517
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : Consultant en sécurité
    Secteur : High Tech - Opérateur de télécommunications

    Informations forums :
    Inscription : Mai 2007
    Messages : 11 517
    Points : 50 367
    Points
    50 367
    Par défaut
    J'ose quand même donner ma solution qui se base sur setjmp() et longjmp().

    setjump() sauvegarde le contexte du programme appelant (la pile) et longjump() peut être appelé n'importe quand par une fonction va restaurer le contexte sauvegarder et donc reprendre le déroulement juste après le setjump().

    C'est l'équivalent d'un goto inter fonction (ce qui n'est pas possible avec un goto classique).

    La question que je me pose maintenant, comme c'est un forum c++, est ce que les destructeurs des objets seront appelés ou pas, je n'en sais rien. Il faudrait tester.

    Je pense quand même que cette solution n'est pas très propre et je ne l'utiliserai qu'en cas de force majeure.
    Raymond
    Vous souhaitez participer à la rubrique Réseaux ? Contactez-moi

    Cafuro Cafuro est un outil SNMP dont le but est d'aider les administrateurs système et réseau à configurer leurs équipements SNMP réseau.
    e-verbe Un logiciel de conjugaison des verbes de la langue française.

    Ma page personnelle sur DVP
    .

  3. #3
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Pour être sûr, autant utiliser une exception directement.
    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
    void Menu::GUI_Main()
    {
        unsigned int i;
        try
        {
            while(1)
            {
                SDL_Delay(10);
                for(i=0;i<evenements.size();i++)
                    evenements[i](this);
            }
        }
        catch (EndException& e)
        {
        }
    }
     
    void Menu::exit_Menu()
    {
        throw EndException();
    }
    ... mais c'est à peine mieux.
    Pourquoi ne pas utiliser tout simplement un booléen membre, du style :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    class Menu
    {
        private :
            std::vector<Objet*> sous_objets;
            std::vector<Evenement> evenements;
            bool end;
            //Ceci est un exemple simplifiÉ et donc on ne marquera pas tout.
        public :
            void GUI_Main();
            void exit_Menu();
            //Ceci est un exemple simplifiÉ et donc on ne marquera pas tout.
    };
    ... puis :
    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
    void Menu::GUI_Main()
    {
        unsigned int i;
        while(!end)
        {
            SDL_Delay(10);
            for(i=0;i<evenements.size() && !end;i++)
                evenements[i](this);
        }
    }
     
    void Menu::exit_Menu()
    {
        end = true;
    }
    La seule différence avec le code utilisant les jumps ou les exceptions, c'est que exit_Menu() ne quitte pas immédiatement le menu. Mais peut être que tu t'en fiches ?

  4. #4
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Kalith, c'est la solution que je comptais adopter à defaut d'autres. Cependant, j'aurais préféré que le menu s'exit tout de suite et je pense que ta solution ralentit l'éxécution (comparé à un longjmp). Le temps d'éxécution est primordial pour un GUI qui va bouclé dans cette boucle plus de 50 fois par seconde.
    Ce qui fonctionnerais (mais je pense que le temps d'exécution pourrait être nettement ralentit) est :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    void Menu::GUI_Main()
    {
        unsigned int i;
        while(1)
        {
            SDL_Delay(10);
            for(i=0;i<evenements.size() ;i++)
                if(!evenements[i](this))
                    goto end;
        }
        end;
    }
    Dans ce cas, il n'y aurais pas besoin d'un exit_Menu();

    ram-0000, je pars étudier les longjmp.
    De plus, dans l'exemple montré (et je ne pense pas en avoir dans l'exemple réel), je n'ai pas de destructeur appelé dans la boucle while.
    Merci pour votre aide. Si quelqu'un a une autre solution que goto, longjmp,...
    L'important est tout de même la vitesse d'éxécution et non la relecture du code.

    [EDIT] J'avais oublié la méthode de l'exception. Est-ce aussi rapide qu'un longjmp ? aussi propre (vu qu'on ne l'utilise pas réellement pour une erreur) ?

  5. #5
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Je viens juste de tester longjmp (sa marche parfaitement) avec ce code :

    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
    #include <iostream>
    #include <setjmp.h>
     
    using namespace std;
    class Menu
    {
        private :
            jmp_buf end;
            //Ceci est un exemple simplifier et donc on ne marquera pas tout.
        public :
     
            void GUI_Main();
            void exit_Menu();
            //Ceci est un exemple simplifier et donc on ne marquera pas tout.
    };
     
     
    int main()
    {
        Menu menu;
        menu.GUI_Main();
        cout<<"FINI";
        return 0;
    }
     
    void Menu::exit_Menu()
    {
        longjmp(end,1);
    }
     
    void Menu::GUI_Main()
    {
        unsigned int i;
        int exit;
        exit=setjmp(end);
        while(!exit)
        {
            exit_Menu();
        }
    }
    Y a t-il plus efficace ?

    Je n'ai pas testé si les delete étés faits.

  6. #6
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    La variable d'état interne ou le retour sur un booléen me semble encore les approches les plus faciles à maintenir et comprendre.
    Quand à la rapidité ? Face à un Delay(10), la remonté de la pile devrait être plus rapide , non ?

  7. #7
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    3dArchi, en effet face à un Delay(10), un if dans un for ne changera rien.
    Mais imaginons que j'ai quelques milliers d'Evenements, que faire alors ?
    Un tour de for = 5000 if de trop + Delay(10).
    Je n'ai aucune idée du temps pris par 5000 if mais ça doit devenir suffisamment pour être pris en compte ?
    Et même si c'est négligeable, étant sur un projet ayant pour but de me perfectionné, je souhaiterais trouver une solution plus satisfaisante.
    De plus, si un jour j'arrive à rendre ce GUI utilisable, l'utilisateur n'aura pas a savoir que je fais un longjmp ou une exception dans mon code.



    Pour le lancé d'exception, si quelqu'un lance un catch dans un evenement, alors, le exit_Menu ne marchera plus et l'utilisateur se retrouvera avec une exception qui le concerne pas. Comment empêcher ce problème ?
    Je n'ai jamais compris comment marchais le mécanisme des exceptions (bien que je sache l'utiliser), quelqu'un aurait-il un lien pour m'aider à comprendre si le try est un gros if et throw un goto ou si c'est quelque chose de totalement différent ?

    [EDIT] De plus, le SDL_Delay(10) sert juste à ne pas monopoliser le processeur. Il se peut qu'il soit changé ou laissé à l'utilisateur de choisir.

  8. #8
    Membre éclairé

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2007
    Messages
    373
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 35
    Localisation : Royaume-Uni

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Santé

    Informations forums :
    Inscription : Juin 2007
    Messages : 373
    Points : 764
    Points
    764
    Par défaut
    Normalement un autre bloc catch ne devrait pas intercepter l'exception.
    Mettons que tu ais ce genre d'exceptions :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    class UneAutreException : public ExceptionBase
    {
        //...
    };
     
    class EndException : public ExceptionBase
    {
        //...
    };
    Alors :
    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
     
    try
    {
        //...
    }
    catch (...)
    {
        // Intercepte absolument tout
    }
     
    try
    {
        //...
    }
    catch (ExceptionBase& e)
    {
        // Intercepte toutes les exceptions qui dérivent de ExceptionBase, donc UneAutreException et EndException
    }
     
    try
    {
        // ...
    }
    catch (UneAutreException& e)
    {
        // Intercepte seulement UneAutreException, et pas EndException
    }
    Il faut donc juste faire attention à ce que le code exécuté par chaque événement ne catch pas EndException, donc pas de catch(...) etc.

  9. #9
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Malheureusement, je ne peux contrôler l'utilisateur de ma peut être future bibliothèque. Je ne peux garantir l'absence d'un catch(...).
    Concernant la rapidité et le fonctionnement du mécanisme d'exception en c++ quelqu'un a t-il une idée? un lien ?

  10. #10
    Rédacteur
    Avatar de 3DArchi
    Profil pro
    Inscrit en
    Juin 2008
    Messages
    7 634
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Juin 2008
    Messages : 7 634
    Points : 13 017
    Points
    13 017
    Par défaut
    Salut,
    Citation Envoyé par NoIdea Voir le message
    Je n'ai aucune idée du temps pris par 5000 if mais ça doit devenir suffisamment pour être pris en compte ?
    j'en doute.
    Citation Envoyé par NoIdea Voir le message
    Et même si c'est négligeable, étant sur un projet ayant pour but de me perfectionné, je souhaiterais trouver une solution plus satisfaisante.
    Objectif louable mais en quoi l'utilisation d'une variable interne ou d'un retour booléen n'est pas satisfaisant
    Perso, je trouve plus étrange le Delay et le fait que tu fais une boucle pour appeler tous les gestionnaires d'évènements. En général, un seul est appelé quand l'évènement attendu est déclenché.

    Sinon, il est toujours intéressant de regarder comment d'autres ont fait. wxWidgets ou Qt ont des sources libres. Tu peux toujours jetter un coup d'oeil pour voir s'il y a des idées intéressantes.

  11. #11
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Dans mon GUI, chaque objets à un vector d'evenements. Ces foncteurs evenements possèdent au moins l'Objet appelant :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    class Evenement
    {
        public :
            Objet* appelant;
            Evenement();
            virtual void/*ou bool*/ operator ()()=0;
     
    };
    Un exemple d'evenement, serais :

    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
    class Appuyer_Bouton : public Evenement
    {
        private :
            bool was_pressed;
    };
     
    void Appuyer_Bouton::operator()()
    {
        if(is_on_object(get_mouse_pos(), appelant)&& mouse_is_pressed())
        {
            Bouton*ptr=static_cast<Bouton*>(appelant);
            ptr->enfoncer();
            was_pressed=true;
        }
        else if(is_on_object(get_mouse_pos(), appelant)&& (!mouse_is_pressed())&& was_pressed)
        {
            Bouton*ptr=static_cast<Bouton*>(appelant);
            ptr->relacher();
            was_pressed=false;
            get_top_parent(appelant)->exit_Menu();//On sort du Menu et commence le jeu.    
         }
    }
    Mon GUI contrairement à Qt, GTK et surement wxwidget ne se base pas sur le systeme des signaux.
    L' "Evenement" ci-dessus serais automatiquement intégrés lors du constructeur de la classe Bouton.
    Cependant, un peu à la méthode des signaux, j'aurais aimé pouvoir "linker" des fonctions : Quand telle fonction est appelée, tu m'appelle au celle-ci juste avant/après. Mais cela fera peut être l'objet d'un autre thread.

    Si vous pensez que cette méthode pour gérer les évènements n'ai pas viable j'aimerais le savoir (si possible avec les raisons).
    Pour en revenir au sujet de départ, je vais tester si longjmp "saute" les destructeur. Si oui, je prendrais soit les exceptions ou le retour d'un booléen.

  12. #12
    Modérateur
    Avatar de bruno_pages
    Homme Profil pro
    ingénieur informaticien à la retraite
    Inscrit en
    Juin 2005
    Messages
    3 533
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 64
    Localisation : France, Essonne (Île de France)

    Informations professionnelles :
    Activité : ingénieur informaticien à la retraite
    Secteur : High Tech - Produits et services télécom et Internet

    Informations forums :
    Inscription : Juin 2005
    Messages : 3 533
    Points : 6 709
    Points
    6 709
    Par défaut
    Citation Envoyé par NoIdea Voir le message
    je vais tester si longjmp "saute" les destructeur. Si oui, je prendrais soit les exceptions ou le retour d'un booléen.
    pas besoin de tester, il va bien les sauter car longjmp est une fonction C non spécialisable pour C++. Pour que les destructeurs soient appelés il faut que cela soit prévu dans le code généré partout où il y a des instances placées dans la pile dont la classe à un destructeur (éventuellement via héritage).

    les exceptions ont été introduite principalement pour palier à ce problème
    Bruno Pagès, auteur de Bouml (freeware), mes tutoriels sur DVP (vieux, non à jour )

    N'oubliez pas de consulter les FAQ UML et les cours et tutoriels UML

  13. #13
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 069
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 069
    Points : 12 113
    Points
    12 113
    Par défaut
    Les exceptions, c'est pour le traitement des erreurs exceptionnelles, pas pour sortir d'une boucle.

    Tout framework d'IHM utilise un modèle évènementiel et évite les boucles.
    Donc une boucle sur l'arrivé d'un évènement qui soit bloquant (pas de ressources inutilement gaspillées), traitement des évènement un par un et dès qu'ils arrivent. Cela simplifie aussi grandement l'utilisation du multithreading.

  14. #14
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    bacelar, d'après mes souvenirs, ni Qt ni GTK ne proposent de moyens pour sortie de leur "main" (gtk_main ou app.exec).
    Dans mon cas, je souhaite en fournir un.
    De plus, je ne vois pas de moyen efficace pour introduire un "nouvel evenement".
    Dans GTK, les évenements sont prédéfinis il me semble. Mais comment introduire l'evenement "si à l'adresse "mon_pointeur", l'octet change, alors...
    Dans Qt cependant, on peut créer des evenements grâce à emit. Cependant, si on reprend mon exemple de voir si l'octet change à une adresse donnée, il faudrait tester en continue cette valeur et donc faire un while(1).

    Il me semble donc que mon système est surement plus fléxible et facile d'utilisation (surtout si j'arrive à faire mes fonctions "linkées").

    Les exceptions, c'est pour le traitement des erreurs exceptionnelles, pas pour sortir d'une boucle.
    Tout à fait d'accord. Mais quelle solution utiliser ?

  15. #15
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 069
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 069
    Points : 12 113
    Points
    12 113
    Par défaut
    ni Qt ni GTK ne proposent de moyens pour sortie de leur "main" (gtk_main
    gtk_main_quit()

    De plus, je ne vois pas de moyen efficace pour introduire un "nouvel evenement".
    Une file de message fait largement l'affaire.
    Un nouvel événement, c'est ajouter un message dans la file.
    Traiter un message, c'est le sortir de la file et appelé la fonction ou la méthode associé.

    Si d'oit avoir des suscriptions, l'implémentation du Design Pattern Observer fait l'affaire.

    gtk_main_quit(), doit, à mon avis posté un message type WM_QUIT.

    Mais comment introduire l'evenement "si à l'adresse "mon_pointeur", l'octet change, alors...
    Le code modifiant post un message de Notification de changement.

    change à une adresse donnée, il faudrait tester en continue cette valeur et donc faire un while(1).
    Non, il faut juste que le code modifiant la valeur notifie ce changement, soit par message (file de message) soit par utilisation du Design Pattern observer.

    Il me semble donc que mon système est surement plus fléxible et facile d'utilisation (surtout si j'arrive à faire mes fonctions "linkées").
    Plus flexible ? En quoi ? Un exemple par rapport à une file de messages ou des observers ?
    Facile d'utilisation ? Idem

  16. #16
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Merci pour le gtk_main_quit(), je ne l'avais jamais utilisé (s'il existe la même chose pour Qt, je prend...).

    Imaginons maintenant que notre octet et volatile, comment le on_change fonctionnera (autrement que while(1) sur un autre thread) ?

    D'un point de vue performance, la gestions des signaux est-elle beaucoup plus efficace que ma méthode ?

    La raison pour laquelle je trouve ma forme plus flexible, c'est que dans Qt, le signal et le slot doivent avoir la même signature ce qui oblige parfois à passer par une fonction intermédiaire.

    De plus, dans GTK, tous les paramètres sont passés en void* (dans la version c en tout cas : je n'ai jamais testé le wrapper c++).
    Dans mon cas, c'est contraintes n'existent pas (il me semble).

  17. #17
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 069
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 069
    Points : 12 113
    Points
    12 113
    Par défaut
    (s'il existe la même chose pour Qt, je prend...).
    Google est ton ami : "QApplication::eventLoop()->exitLoop()"

    Imaginons maintenant que notre octet et volatile, comment le on_change fonctionnera (autrement que while(1) sur un autre thread) ?
    Avec ton approche aussi, le thread qui est en attente active, n’a aucune garantie qu'un autre thread n'ait pas modifié la valeur depuis la première modification.

    Avec une file : soit se qui est important c'est le fait qu'il y a eu modification et un message de notification simple fait l'affaire, soit la valeur au moment de la modification est importante et le message contiendra toutes les valeur nécessaire au traitement donc les valeurs volatiles.
    Cette implémentation permet l'utilisation du Design Pattern Command, garantissant la non perte de données transitoire contrairement à une boucle active.

    Avec un observer, le code de modification appels les méthodes dans le contexte de la modification et dans le même thread. Même problème que pour une boucle active mais le temps de réaction et nul car c'est le thread qui modifie appel les routines à notifier.

    D'un point de vue performance, la gestions des signaux est-elle beaucoup plus efficace que ma méthode ?
    D'un point de vue performance, toutes les méthodes sont meilleures qu'une attente active. Comptez le nombre de cycle machine perdu et du manque de réactivité dû au
    SDL_Delay(10);
    La raison pour laquelle je trouve ma forme plus flexible, c'est que dans Qt, le signal et le slot doivent avoir la même signature ce qui oblige parfois à passer par une fonction intermédiaire.

    De plus, dans GTK, tous les paramètres sont passés en void* (dans la version c en tout cas : je n'ai jamais testé le wrapper c++).
    Pas de problème avec le Design Pattern Observer.
    Avec une file de message, cela est très facilement éliminé par l'implémentation d'une fonction de décodage des types messages et de transformation des paramètres.

    Attente Active, c'est de la m****.

  18. #18
    Membre actif

    Profil pro
    Inscrit en
    Avril 2010
    Messages
    356
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Avril 2010
    Messages : 356
    Points : 206
    Points
    206
    Par défaut
    Merci pour toutes ces réponses, je pars me renseigner sur les différents design pattern cités en espérant que mon niveau suivra..

  19. #19
    Expert éminent sénior
    Avatar de koala01
    Homme Profil pro
    aucun
    Inscrit en
    Octobre 2004
    Messages
    11 612
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : Belgique

    Informations professionnelles :
    Activité : aucun

    Informations forums :
    Inscription : Octobre 2004
    Messages : 11 612
    Points : 30 612
    Points
    30 612
    Par défaut
    Salut,

    De manière générale, j'ai horreur de créer des boucles définitivement infinies, ce qui fait que, plutôt que d'avoir un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while(1) /* ou while(true)
    {
        /*...*/
    }
    je préfère encore avoir un
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    while(variableBooleenne)
    {
        /*...*/
    }
    qui me permette, le cas échéant, de modifier la "variableBooleenne" afin de sortir de la boucle.

    Pour ce qui en est de la gestion des événements, le mieux me semble de passer par... une file d'événements:
    Chaque fois qu'un événement survient, tu le rajoute à la fin de la file, et tu crées une boucle qui... gère les événement survenus dans l'ordre dans lequel ils sont apparus.

    Tu aurais donc une classe de base proche de
    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
    class Event
    {
        public:
            Evenement(/* parametres eventuels */)
            virtual ~Evenement() = 0;
            virtual void /* ou bool */ compute() = 0;
    };
    class Quit : public Event
    {
        public:
            Quit(EventManager * em):em_(em){}
            /* !!! devrait normalement être implémenté hors de la classe :D */
            virtual void /* ou bool */ compute()
            {
                em_->again_ = false;
            }
        private:
            EventManager * em_;
    }
    dont dériverait tous les événements susceptibles de se produire, et enfin une file d'événements proche de
    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
    class EventManager
    {
        /*j'ai quelques scrupules à mettre un mutateur sur again_ alors qu'il n'y
         * aura que l'événement "Quit" qui devra en modifier la valeur
         */
        friend class Quit; 
        public:
            /* quand on crée le gestionnaire, il doit, par défaut, continuer
             * jusqu'à plus ample informé
             */
            EventManager():again_(true){}
            /* la fonction qui permet de rajouter un événement à la liste */
            void /* ou bool  */ addEvent(Event* e)
            {
                 items_.push(e)
            }
            void /* ou bool */ execute()
            {
               /* tant qu'il y a des événements à gérer
                while(!items_.empty())
                {
                    /* on gère le premier de la liste */
                    items_.front()->compute();
                    /* on le détruit correctement (pour éviter les fuites mémoires*/
                    delete items_.front();
                    /* et on le retire */
                    items_.pop();
                }
            }
            /* permet de déterminer s'il faut sortir de la boucle de la fonction
             * principale
             */
            bool again() const {return again_;}
        private:
            /* la variable que l'événement indiquant le souhait de quitter doit 
             * modifier
             */
            bool again_;
    };
    Avec, dans la fonction principale, quelque chose comme
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    int main()
    {
        EvenementManager em;
        while (em.again())
        {
            em.execute();
            /* on pourrait parfaitement en rester là :D
             * ou, plus surement, faire en sorte que les événements suivants 
             * soient correctement ajoutés :D 
             */
        }
        return 0;
    }
    C'est simple, et efficace
    A méditer: La solution la plus simple est toujours la moins compliquée
    Ce qui se conçoit bien s'énonce clairement, et les mots pour le dire vous viennent aisément. Nicolas Boileau
    Compiler Gcc sous windows avec MinGW
    Coder efficacement en C++ : dans les bacs le 17 février 2014
    mon tout nouveau blog

  20. #20
    Expert éminent sénior
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Février 2005
    Messages
    5 069
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Val de Marne (Île de France)

    Informations professionnelles :
    Activité : Développeur informatique
    Secteur : Conseil

    Informations forums :
    Inscription : Février 2005
    Messages : 5 069
    Points : 12 113
    Points
    12 113
    Par défaut
    Reste plus qu'à supprimer l'attente active et avoir une file de message et les accès à un membre threadsafe.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
     
                    items_.front()->compute();
                    /* on le détruit correctement (pour éviter les fuites mémoires*/
                    delete items_.front();
                    /* et on le retire */
                    items_.pop();
    pas terrible en multi-thread.
    Avec une file custom l'algo devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
     
    while(again)
    {
            /*Appel bloquant tant qu'il n'y a pas de message*/
            Event pev = items_.PopNext()
            ev.compute();
    }

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

Discussions similaires

  1. Récupérer tout ce qui n'est pas dans la base
    Par SnakeBoudoir dans le forum Requêtes
    Réponses: 2
    Dernier message: 01/11/2006, 19h18
  2. Trouver une valeur qui n'est pas dans un champ
    Par eric41 dans le forum Requêtes
    Réponses: 6
    Dernier message: 16/05/2006, 16h48
  3. [RegEx] highlight d'un mot qui n'est PAS dans un tag html.
    Par FMaz dans le forum Langage
    Réponses: 5
    Dernier message: 22/03/2006, 14h07
  4. Importer un .py qui n'est pas dans le rep courant
    Par Mr Hyde dans le forum Général Python
    Réponses: 5
    Dernier message: 25/08/2005, 17h30

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