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

Multithreading Discussion :

Connexion signal-signal-slot : seconde émission en attente du thread ou non ? [QThread]


Sujet :

Multithreading

  1. #1
    Membre actif
    Homme Profil pro
    Freelance
    Inscrit en
    Décembre 2003
    Messages
    423
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Freelance

    Informations forums :
    Inscription : Décembre 2003
    Messages : 423
    Points : 259
    Points
    259
    Par défaut Connexion signal-signal-slot : seconde émission en attente du thread ou non ?
    Bonjour,

    bha voila, ma question est dans le titre
    Pour être plus précis :
    supposons trois Thread T1 T2 et T3

    T2 fait une connexion entre le signal p de T1 avec le signal p de T2
    T2 fait une connexion entre le signal p de T2 avec le slot q de T3

    A l'émission de p depuis T1, Qt va-t-il attendre que T2 soit disponible pour émettre le signal p de T2 (puisque un slot s'exécute normalement dans le Thread de l'objet ayant le slot ... est-ce pareil pour les signaux ?)


    Merci de votre réponse
    "La théorie, c’est quand on sait tout et que rien ne fonctionne. La pratique, c’est quand tout fonctionne et que personne ne sait pourquoi. Ici, nous avons réuni théorie et pratique : rien ne fonctionne ... et personne ne sait pourquoi !" et malheureusement c'est souvent le cas en Développement...

  2. #2
    Membre actif
    Profil pro
    Inscrit en
    Mars 2010
    Messages
    188
    Détails du profil
    Informations personnelles :
    Âge : 37
    Localisation : France

    Informations forums :
    Inscription : Mars 2010
    Messages : 188
    Points : 248
    Points
    248
    Par défaut
    Tout d'abord sache que seul un thread qui est entré dans l'eventloop peut exécuter des slot a la réception de signaux. Pour la suite je te conseil la FAQ
    Et de t'amuser a faire des test toi même (en utilisant QThread::currentThreadId)
    c'est le meilleur moyen de comprendre

  3. #3
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    Je pense que c'est comme pour un slot, le signal sera rémit lors de l'eventloop. Mais je n'en suis pas sure.
    Le mieux est bien sure un petit teste
    Si c'est bloquant tu peut préciser Qt:irectConnection lors du connect entre les deux signaux.

  4. #4
    Inactif  


    Homme Profil pro
    Inscrit en
    Novembre 2008
    Messages
    5 288
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 48
    Localisation : France, Rhône (Rhône Alpes)

    Informations professionnelles :
    Secteur : Santé

    Informations forums :
    Inscription : Novembre 2008
    Messages : 5 288
    Points : 15 620
    Points
    15 620
    Par défaut
    Bonjour

    La réponse me semble pas évidente...

    On est d'accord que QObject::connect crée une connexion de type Qt:: DirectConnection lorsque les QObject émettant et recevant le signal sont dans le même thread (et donc l'appel est direct) et une Qt::QueuedConnection lorsqu'ils sont dans des threads différents (et donc le traitement du signal passe par la boucle d'événements).

    Si on faisait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    emit_de_T1(signal_de_T1) -> slot_de_T2 : emit(signal_de_T2) -> slot_de_T3
    les 2 slots seraient exécutés dans les boucles d'événements de T2 et de T3.

    Dans le cas d'un signal vers un autre signal, on a 2 informations (légèrement) différentes dans la doc :
    1. on crée une Qt::QueuedConnection lorsque les threads sont différents (http://qt.developpez.com/doc/latest/...ctionType-enum)
    2. la connexion signal->signal est directe (http://qt.developpez.com/doc/latest/...sandslots.html)
    It is even possible to connect a signal directly to another signal. (This will emit the second signal immediately whenever the first is emitted.)
    A priori, je dirais que le signal de T2 est émis tout de suite, sans passer par la boucle d'événements (pour moi, le point 1 s'applique que pour les connections signal->slot)

    Pour tester, je ne pense pas que QThread::currentThreadId puisse servir (il faudrait le mettre dans un slot de T2 et donc cela pourrait modifier le comportement de la connexion).
    Tu peux peut être tester en lancer une boucle d'évènements infinie dans T2 et vérifier :
    1. qu'en utilisant un slot dans T2 qui émet vers T3 ne passe jamais
    2. qu'en connectant le signal de T1 avec le signal de T2, le slot T3 est exécute.

    Si tu fais des tests, tu pourrais mettre le résultat (et le code) ici, pour notre culture générale ?

    Au fait, pourquoi cette question ?

  5. #5
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    si la doc le dit, c'est que ça doit être directe.

    Comme un signal est threadsafe, il ne peut pas y avoir de problème. Ça parait cohérent.

  6. #6
    Membre actif
    Homme Profil pro
    Freelance
    Inscrit en
    Décembre 2003
    Messages
    423
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Freelance

    Informations forums :
    Inscription : Décembre 2003
    Messages : 423
    Points : 259
    Points
    259
    Par défaut
    Bonjour,

    Tout d'abord merci de votre intérêt et investissement pour ma question.

    Comme l'a dit gbdivers,personnellement je ne trouvais pas ça spécialement évident (j'ai bien consulté la FAQ avant de venir ici évidemment) et la solution via un test ne m'est pas directement venu à l'esprit mais grâce à vos remarques, je vais pouvoir tester ça.

    Cela dit, de part la réponse assez complète de gbdivers, je pense qu'on peut effectivement s'attendre à ce que le signal de T2 soit émis directement. Laissez-moi quelques minutes, je fais un petit programme de test et je vous envoi le code et son résultat

    Au fait, pourquoi cette question ?
    Je suis en train de concevoir une application, et je constate qu'il est probable que je me retrouve dans cette situation (loin d'être sûr encore). Alors avant d'aller droit dans le mur, je cherche à savoir comment l'émission de ce signal va se passer. Mon problème est que si l'émission du signal de T2 attend que le celui-ci soit disponible, je ne peux pas conserver la conception actuelle (point de vue performances).
    Concrètement, entre autres j'ai :

    1. Le main thread
    2. un thread de traitement
    3. un thread d'analyse

    Ce que je veux c'est que, à la fin de l'analyse, le traitement exécute une série d'actions (étant donné des valeurs récupérées depuis l'analyse) et que l'analyse se remette alors à analyser de nouvelles données. Comme le traitement et l'analyse ne se connaissent pas, je dois signaler la fin de mon analyse au traitement en passant par le main thread. Or je ne veux pas que l'émission du signal soit ralentit parce que le main thread est occupé.
    Si Qt est capable de gérer ça ... je continue tel quel. Maintenant si c'est pas possible, il va juste falloir que je trouve un moyen pour que analyse connaisse traitement et s'y connecte tout seul et directement ou alors synchroniser mes threads via un semaphore

    Ai-je répondu à la question ?

    Merci encore et à dans quelques minutes pour le test
    "La théorie, c’est quand on sait tout et que rien ne fonctionne. La pratique, c’est quand tout fonctionne et que personne ne sait pourquoi. Ici, nous avons réuni théorie et pratique : rien ne fonctionne ... et personne ne sait pourquoi !" et malheureusement c'est souvent le cas en Développement...

  7. #7
    Membre actif
    Homme Profil pro
    Freelance
    Inscrit en
    Décembre 2003
    Messages
    423
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Freelance

    Informations forums :
    Inscription : Décembre 2003
    Messages : 423
    Points : 259
    Points
    259
    Par défaut
    Re bonjour,

    Ok j'ai finalement fait les tests nécessaires (enfin je crois ). Finalement, la réponse semble être la suivante :
    Par défaut, Qt, même s'il s'agit d'une connexion SIGNAL <-> SIGNAL, va attendre que le thread cible concerné soit disponible avant de transmettre le SIGNAL.
    Cela dit en forçant la connexion avec un Qt:irectConnection, le signal est transmis même si le thread cible n'est pas disponible (tel est le but de Qt:irectConnection vous me direz).

    Pour vérifier cela j'ai utilisé le mini programme suivant (attention, soyons bien clair, c'est un programme de tests : la libération de la mémoire n'est pas gérée et y'avait certainement moyen de faire plus propre notamment au niveau de l'encapsulation, mais là n'était pas l'objectif du test) :

    ObjetTest
    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
     
    //////////////////////////////////////// ObjetTest.h
    #ifndef OBJETTEST_H
    #define OBJETTEST_H
    #include <QObject>
     
    class ObjetTest: public QObject
    {
        Q_OBJECT
     
        public:
            ObjetTest();
     
        public slots:
            void Emettre();
            void Recevoir();
     
        signals:
            void signal();
     
    }; // class ObjetRecepteur
     
    #endif
     
    ///////////////////////////////// ObjetTest.cpp
    #include "ObjetTest.h"
    #include <QDebug>
     
    ObjetTest::ObjetTest()
        :QObject()
    {}
     
    void ObjetTest::Emettre()
    {
        qDebug() << "Emission signal";
        emit signal();
    }
     
    void ObjetTest::Recevoir()
    {
        qDebug() << "Signal reçu";
    }

    ThreadTest
    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
     
    ///////////////////////// ThreadTest.h
    #ifndef THREADTEST_H
    #define THREADTEST_H
     
    #include <QThread>
    #include <QSemaphore>
    #include "ObjetTest.h"
     
    class ThreadTest: public QThread
    {
        Q_OBJECT
     
        public:
            ThreadTest(QSemaphore& _synchro, bool inf = false);
            void Emettre();
     
            ObjetTest* Objet;
     
        signals:
            void lancerSignal();
     
        protected:        
            QSemaphore& synchro;
            bool infini;
            void run();        
    }; // class ThreadTest
     
    #endif
     
     
    ///////////////////////// ThreadTest.cpp
    #include "ThreadTest.h"
    #include <QDebug>
     
     
    ThreadTest::ThreadTest(QSemaphore& _synchro, bool inf)
        :QThread(), synchro(_synchro), infini(inf)
    {}
     
    void ThreadTest::Emettre()
    {
        emit lancerSignal();
    }
     
    void ThreadTest::run()
    {
        Objet = new ObjetTest();
        connect(this,SIGNAL(lancerSignal()), Objet, SLOT(Emettre()));
        synchro.release(1);
        if(infini)
            for(;;);
        exec();
    }

    Main.cpp

    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
     
    #include <QCoreApplication>
    #include <QSemaphore>
    #include <QObject>
     
    #include "ThreadTest.h"
    #include "ObjetTest.h"
     
    int main(int argc, char *argv[])
    {
        QCoreApplication app(argc, argv);
        QSemaphore synchro;
     
        ThreadTest T1(synchro);         T1.start();
        ThreadTest T2(synchro,true);    T2.start();
        ThreadTest T3(synchro);         T3.start();    
     
        synchro.acquire(3);
     
        /* Scénario 1 */
        //QObject::connect(T1.Objet,SIGNAL(signal()), T2.Objet, SIGNAL(signal()));
     
        /* Scénario 2 */
        QObject::connect(T1.Objet,SIGNAL(signal()), T2.Objet, SIGNAL(signal()), Qt::DirectConnection);
     
     
        QObject::connect(T1.Objet,SIGNAL(signal()), T2.Objet, SLOT(Emettre()));
        QObject::connect(T2.Objet,SIGNAL(signal()), T3.Objet, SLOT(Recevoir()));
     
     
        T1.Emettre();
     
        return app.exec();
    }
    Les résultats d'exécution sont les suivants :
    Scénario 1:
    Emission signal
    Scénario 2:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
     
    Emission signal 
    Signal reçu
    Ce qui confirme bien que l'on est pas entré dans le Thread de T2 mais que le signal a bien été transmis ... mais bon ... il a fallu qu'on force la main à Qt.
    Ce qui donc sous-entend que l'assertion
    It is even possible to connect a signal directly to another signal. (This will emit the second signal immediately whenever the first is emitted.)
    n'est pas valide ... (ou me trompe-je ?) ... faudrait-il le leur signaler (sans mauvais jeu de mots bien évidemment ) ?


    Voilà pour la réponse à la question finalement.

    Merci pour votre contribution
    "La théorie, c’est quand on sait tout et que rien ne fonctionne. La pratique, c’est quand tout fonctionne et que personne ne sait pourquoi. Ici, nous avons réuni théorie et pratique : rien ne fonctionne ... et personne ne sait pourquoi !" et malheureusement c'est souvent le cas en Développement...

  8. #8
    yan
    yan est déconnecté
    Rédacteur
    Avatar de yan
    Homme Profil pro
    Ingénieur expert
    Inscrit en
    Mars 2004
    Messages
    10 033
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 42
    Localisation : France, Ille et Vilaine (Bretagne)

    Informations professionnelles :
    Activité : Ingénieur expert
    Secteur : High Tech - Multimédia et Internet

    Informations forums :
    Inscription : Mars 2004
    Messages : 10 033
    Points : 13 968
    Points
    13 968
    Par défaut
    ou comment faire chauffer son proc
    sinon, teste très bien fait.

    Voici ton code en 1 seule fichier main (plus facile pour tester)
    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
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    #include <QtCore>
    class ObjetTest: public QObject
    {
        Q_OBJECT
     
        public:
            ObjetTest( ){}
     
        public slots:
            void Emettre()
            {
                qDebug() << "Emission signal";
                emit signal();
            }
            void Recevoir()
            {
                qDebug() << "Signal reçu";
            }
     
        signals:
            void signal();
     
    }; // class ObjetRecepteur
     
    class ThreadTest: public QThread
    {
        Q_OBJECT
     
        public:
            ThreadTest(QSemaphore& _synchro, bool inf = false)
                :QThread(), synchro(_synchro), infini(inf)
            {}
            void Emettre()
            {
                emit lancerSignal();
            }
     
            ObjetTest* Objet;
     
        signals:
            void lancerSignal();
     
     
        protected:
            QSemaphore& synchro;
            bool infini;
            void run()
            {
                Objet = new ObjetTest();
                connect(this,SIGNAL(lancerSignal()), Objet, SLOT(Emettre()));
                synchro.release(1);
                if(infini)
                {
                    forever
                    {
                        QThread::sleep(10000);
                    }
     
                }
     
                exec();
            }
    }; // class ThreadTest
     
     
    #include "main.moc"
     
    int main(int argc, char *argv[])
    {
        QCoreApplication app(argc, argv);
            QSemaphore synchro;
     
            ThreadTest T1(synchro);         T1.start();
            ThreadTest T2(synchro,true);    T2.start();
            ThreadTest T3(synchro);         T3.start();
     
            synchro.acquire(3);
     
            /* Scénario 1 */
            //QObject::connect(T1.Objet,SIGNAL(signal()), T2.Objet, SIGNAL(signal()));
     
            /* Scénario 2 */
            QObject::connect(T1.Objet,SIGNAL(signal()), T2.Objet, SIGNAL(signal()), Qt::DirectConnection);
     
     
            QObject::connect(T1.Objet,SIGNAL(signal()), T2.Objet, SLOT(Emettre()));
            QObject::connect(T2.Objet,SIGNAL(signal()), T3.Objet, SLOT(Recevoir()));
     
     
            T1.Emettre();
     
            return app.exec();
    }

    Citation Envoyé par Bleys Voir le message
    Ce qui donc sous-entend que l'assertion n'est pas valide ... (ou me trompe-je ?) ...
    faudrait-il le leur signaler (sans mauvais jeu de mots bien évidemment ) ?
    Après avoir lue et relue le paragraphe, je pense que c'est juste mal expliqué et trés raccourcie. C'est surement pour dire, si on utilise une connection directe, qu'un signal peut appeler un autre signal de manière directe sans prendre en compte l'appartenance aux thread.

    on pourrais traduire
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    connect a signal directly to another signal
    connecter un signal de manière directe à un autre signal.

    Ca vaut surement le coup de leur demander une meilleur explication.

    ps :

  9. #9
    Membre actif
    Homme Profil pro
    Freelance
    Inscrit en
    Décembre 2003
    Messages
    423
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 37
    Localisation : France

    Informations professionnelles :
    Activité : Freelance

    Informations forums :
    Inscription : Décembre 2003
    Messages : 423
    Points : 259
    Points
    259
    Par défaut
    Salut,

    ou comment faire chauffer son proc
    Heyhey ... moi je suis un peu bête et méchant parfois .... on me dit "thread infini" => blam voilà ... Je referai plus promis

    Voici ton code en 1 seule fichier main (plus facile pour tester)
    Effectivement j'aurai pu faire ça un en seul fichier ... j'étais tellement dans mes réflexion dernièrement que ... j'ai bêtement repris les structures en place

    Après avoir lue et relue le paragraphe, je pense que c'est juste mal expliqué et trés raccourcie. C'est surement pour dire, si on utilise une connection directe, qu'un signal peut appeler un autre signal de manière directe sans prendre en compte l'appartenance aux thread.

    on pourrais traduire
    Code :
    connect a signal directly to another signal
    connecter un signal de manière directe à un autre signal.
    Effectivement, je n'avais pas fait attention au terme "directly" qui sous-entend peut-être de devoir ajouter l'option DirectConnection. Bien vu


    Encore une fois merci à tout ceux qui ont pu intervenir et m'aider pour cette question
    "La théorie, c’est quand on sait tout et que rien ne fonctionne. La pratique, c’est quand tout fonctionne et que personne ne sait pourquoi. Ici, nous avons réuni théorie et pratique : rien ne fonctionne ... et personne ne sait pourquoi !" et malheureusement c'est souvent le cas en Développement...

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

Discussions similaires

  1. Connexion entre signal et slot
    Par illyria86 dans le forum Débuter
    Réponses: 6
    Dernier message: 15/01/2011, 18h45
  2. probleme de code Qt: signal and Slot
    Par vivh349 dans le forum Qt
    Réponses: 10
    Dernier message: 08/07/2009, 12h17
  3. Réponses: 4
    Dernier message: 16/04/2008, 17h04
  4. connect Signal et slot perso
    Par freecircus dans le forum Qt
    Réponses: 3
    Dernier message: 13/12/2006, 20h25
  5. Connexion "directe" signal - slot
    Par broidsy dans le forum Qt
    Réponses: 3
    Dernier message: 27/02/2006, 09h37

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