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

GTK+ avec C & C++ Discussion :

boucle de fond bloquée par app->run(*p_main_window)


Sujet :

GTK+ avec C & C++

Vue hybride

Message précédent Message précédent   Message suivant Message suivant
  1. #1
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2012
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2012
    Messages : 114
    Par défaut boucle de fond bloquée par app->run(*p_main_window)
    Bien le bonjour,
    je bosse sur raspbian stretch installé depuis noobs sur raspberry pi 3B.
    Je développe une appli avec IHM glade+gtk3mm, en c++.
    Je ne suis pas très à l'aise avec les termes à utiliser et suis plutôt débutant dans ces technologies.

    J'ai déjà développé une appli dont le main se contentait, après qq initialisations, de lancer l'interface graphique. Puis toutes les actions étaient provoquées par des interruptions, de type timer ou de type hardware. Le main ressemblait à cela :
    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
    53
    54
    55
    56
    57
    58
    59
     
    /**************/
    /* main         */
    /**************/
    int main (int argc, char *argv[])
    {
      //auto app = Gtk::Application::create(argc, argv/*, "org.gtkmm.example"*/);
      auto app = Gtk::Application::create();
     
      //Load the GtkBuilder file and instantiate its widgets:
      auto refBuilder = Gtk::Builder::create();
      try{
        refBuilder->add_from_file("ihm.glade");
      }
      catch(const Glib::FileError& ex){
        std::cerr << "FileError: " << ex.what() << std::endl;
        return 1;
      }
      catch(const Glib::MarkupError& ex)
      {
        std::cerr << "MarkupError: " << ex.what() << std::endl;
        return 1;
      }
      catch(const Gtk::BuilderError& ex){
        std::cerr << "BuilderError: " << ex.what() << std::endl;
        return 1;
      }
     
      refBuilder->get_widget("main_window", p_main_window);
     
    if(p_main_window){
        refBuilder->get_widget("button_Test", p_button_Test);
     
        refBuilder->get_widget("label_Connexion_reseau", p_label_Connexion_reseau);
        if(p_button_Test) p_button_Test->signal_clicked().connect( sigc::ptr_fun(on_button_test_clicked) );
     
        p_main_window->set_size_request(800,480);
        p_main_window->set_title("xx");
     //   p_graph_drawing_area->set_size_request(500,300);
     
      initPin(); //init les gpio
      initIsrIo(); //init ninterruption sur gpio
      signal(SIGALRM, sig_handler);  // init signal interruption sur timer
     
      p_date_label->set_label (horodatageDate());
      g_idle_add(IhmDateRefresh,0);
     
      g_timeout_add(1000, timer_1_s, 0);
      g_idle_add(initAll,0);
      ouvertureLogSession();
     
      app->run(*p_main_window);
     
      }
      }
     
      delete p_main_window;
      return 0;
    }
    Pour cette nouvelle appli, je suis très embêté du fait que l'appel est bloquant. En effet, je voudrais cette fois, après qq initialisations, lancer l'interface graphique puis passer au déroulé de mon programme, sans nécessité d'attendre une interruption pour le déclenchement.
    Je ne sais pas comment m'y prendre. J'ai bien penser à lancer le run dans un autre thread, mais j'ai peur que ça complique beaucoup (en plus de lancer dans un autre thread, complique des mises à jour de l'interface depuis thread du main par exemple).

    Il doit exister une façon de faire, propre, assez accessible, dont vous pourriez me donner le secret ?

    J'espère avoir été clair.

    Bonne journée

  2. #2
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Par défaut
    Bonjour,

    tu ne peux rien faire au fait que run soit bloquant. Le principe même d'une interface graphique c'est de réagir à des événements, et pour réagir à ces événéments, il faut pouvoir les recevoir, les traiter puis attendre de nouveaux événements. C'est la partie "attendre de nouveaux événements" qui fait que cela ne peut qu'êre bloquant. C'est le principe même d'une pompe à événements.

    Il te faut donc au lieu d'adapter GTK+ (ou n'importe quelle interface grapqhique d'ailleurs) à ton usage, adapter ton usage au fonctionnement d'une interface graphique. Cela veut dire dans le cas présent:
    • pas de signaux C ANSI (man 2 signal), qui font mauvais ménage avec GTK+
    • utiliser g_idle_add de préférence ou g_timeout_add_seconds ou g_timeout_add pour demander à GTK+ d'appeler ta callback pour vérifier un état du matériel.


    Il y a sans doute mieux, notamment pour éviter de faire du polling, mais c'est un premier pas.

  3. #3
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2012
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2012
    Messages : 114
    Par défaut
    Bonjour Liberforce, et merci,

    utiliser g_idle_add de préférence ou g_timeout_add_seconds ou g_timeout_add pour demander à GTK+ d'appeler ta callback pour vérifier un état du matériel.
    Dans ma précédente appli, j'utilisais g_idle_add et g_idle_timeout_add essentiellement lorsque je cherchais à rafraichir l'interface graphique (j'avais compris que ça permettait de patienter que l'interface soit "libre" pour y accéder, avec mes mots à moi). Je faisais ces appels depuis des fonctions qui étaient exécutées du fait d'interruptions.

    Mais je ne vois pas bien comment ça va fonctionner dans cette situation. Je vais lancer la boucle de fond, avant de faire le run, via un g_idle? Peux-tu me prèciser l'ordre des choses dans le code et dans le temps?

    Merci

  4. #4
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Par défaut
    g_idle_add, g_timeout_add et g_timeout_add seconds sont des GSource. Ce sont des sources d'événements. Elles envoient des événements dans la pompe à événements (appelée "main loop" dasn la doc GTK+). Cette pompe traite ensuite les événements qui lui arrivent au fil de l'eau. Tu n'as pas mis le code de tes callbacks, et ne dis pas ce que ton interface graphique doit faire en réponse aux changements des tes I/O, alors c'est difficile de te dire exactement quoi faire. Mais le principe est le suivant:

    1. appeler g_idle_add en lui passant une callback
    2. dans cette callback:
    2.1. tu vérifies l'état de tes I/O
    2.2. en fonction des changements d'états, tu déclenche des actions sur tes widgets (changement d'état d'un bouton, ou autre)
    2.3. tu sors de ta callback le plus rapidement possible pour que la pompe a événements puisse continuer à traiter les événements

  5. #5
    Membre confirmé
    Profil pro
    Inscrit en
    Octobre 2012
    Messages
    114
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Octobre 2012
    Messages : 114
    Par défaut
    Bonjour,
    je vais essayer de réexpliquer mieux ce que je cherche à faire
    je voudrai cette fois, après qq initialisations, lancer l'interface graphique, puis passer au déroulé de mon programme, sans nécessité d'attendre une interruption pour le déclenchement
    je ne cherche pas seulement à mettre à jour une l'interface graphique au gré des évènements des I/O, cela je savais le faire dans ma première apllication, de ces 2 façons:
    • interruption sur I/O -> g_idle_add vers mise à jour de l'interface
    • g_idle_time.... -> lecture des I/O périodique pour mise à jour interface

    je veux:
    • préparer l'interface graphique
    • lancer l'interface graphique (run)
    • dérouler un certain nombre de fonctions, dont je nomme l'ensemble "boucle de fond", le coeur du programme, qui peut durer plusieurs minutes (avec des mises à jour de l'interface graphique via des g_idle_add)

    mais le "run" m'empêche d'aller jusqu'au 3° point. Logique.
    Dois-je alors lancer cette boucle de fond via un g_idle_add (ou g_idle_time)? Je ne crois pas, puisque cette boucle est très longue elle ne libérera pas de sitôt la pompe à évènement.

    Me fais-je mieux comprendre?

  6. #6
    Modérateur

    Homme Profil pro
    Développeur informatique
    Inscrit en
    Juin 2009
    Messages
    1 395
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

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

    Informations forums :
    Inscription : Juin 2009
    Messages : 1 395
    Par défaut
    Dans ce cas je vois 2 solutions:
    1. 1 thread à part qui fait tes traitements longs et fait les mises à jour graphiques via g_idle_add
    2. ou bien une machine d'état qui découperait tes traitements en petits morceaux, suffisamment courts pour ne pas bloquer la pompe à événements. Voici un exemple avec la technique du lazy loading.


    Si tu sais déjà comment envoyer au thread principal les actions de mises à jour via g_idle_add, c'est sans doute la soluition la plus simple. Je crois que tu peux utiliser un GTask pour ça.

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 1
    Dernier message: 02/04/2013, 12h49
  2. [Timer] timer bloqué par une boucle for?
    Par Jidefix dans le forum Interfaces Graphiques en Java
    Réponses: 3
    Dernier message: 18/09/2006, 17h12
  3. bloqué par cookie
    Par kidu dans le forum Général JavaScript
    Réponses: 5
    Dernier message: 19/08/2005, 09h59
  4. Site sur CD - javascript bloqué par SP2
    Par loutente dans le forum Général Conception Web
    Réponses: 16
    Dernier message: 17/05/2005, 14h22
  5. Select qui boucle ou se termine par un Ora-01460
    Par PatriceP dans le forum Oracle
    Réponses: 4
    Dernier message: 29/10/2004, 08h53

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