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 :

Gérer deux threads [QThread]


Sujet :

Multithreading

  1. #1
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2011
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 38
    Points : 21
    Points
    21
    Par défaut Gérer deux threads
    Bonjour,

    Je souhaite faire une application de lecture/écriture sur un port série.
    Pour cela, j'ouvre un port en read/write et je lance 2 threads, 1 pour la lecture et 1 pour l'écriture.

    Mes 2 thread fonctionnent si il sont ouvert alternativement en premier (j'ai fait le test de la permutation dans le code).
    Lors de la mise en place du 2ième thread, j'ai l'erreur suivante dans la fenêtre d’exécution :


    QObject::moveToThread: Current thread (0x55a970cd4f70) is not the object's thread (0x55a970fe66f0).
    Cannot move to target thread (0x55a970f5fca0)
    Et bien sur le 2ième thread ne fonctionne as, et là, je ne sais plus quoi faire.
    Est-ce que je fais quelque chose de mal ou est ce que j'ai oublié quelque chose??

    Merci d'avance pour votre aide.

    Voici mon code :

    MainWindows.h
    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 MainWindow : public QMainWindow
    {
        Q_OBJECT
     
        QPushButton* bt_OpenPort = (QPushButton*)(Q_NULLPTR);
        QPushButton* bt_Transmission = (QPushButton*)(Q_NULLPTR);
     
        RS_Tools* m_RS_Tools = (RS_Tools*)(Q_NULLPTR);
        Thread_Exec* threadEmission = (Thread_Exec*)(Q_NULLPTR);
        Thread_Exec* threadReception = (Thread_Exec*)(Q_NULLPTR);
     
    public:
        MainWindow(QWidget *parent = nullptr);
        ~MainWindow();
     
        QPushButton* getBt_OpenPort() const;
     
    public slots:
        void demarrerTransmission();
     
     
    };
    MainWindows.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
    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
    MainWindow::MainWindow(QWidget *parent)
        : QMainWindow(parent)
        , m_RS_Tools( new RS_Tools )
    {
        QWidget* centralWidget = new QWidget(this);
        QGridLayout* layout = new QGridLayout();
     
        bt_OpenPort = new QPushButton("Ouvrir port COM");
        bt_OpenPort->setCheckable(true);
        bt_OpenPort->setChecked(false);
        connect(bt_OpenPort, &QPushButton::toggled, m_RS_Tools, &RS_Tools::initPort );
        layout->addWidget(bt_OpenPort, 0,1);
     
        bt_Transmission = new QPushButton("Demarrer/Arreter transmission");
        bt_Transmission->setCheckable(true);
        bt_Transmission->setChecked(false);
        QObject::connect(bt_Transmission, &QPushButton::toggled, this, &MainWindow::demarrerTransmission, Qt::DirectConnection );
        layout->addWidget(bt_Transmission, 1,1);
     
        centralWidget->setLayout(layout);
        setCentralWidget(centralWidget);
    }
     
    MainWindow::~MainWindow()
    {
        delete threadEmission;
    //    delete threadReception;
        delete m_RS_Tools;
    }
     
     
    QPushButton* MainWindow::getBt_OpenPort() const {
        return bt_OpenPort;
    }
     
     
    void MainWindow::demarrerTransmission()
    {
        qDebug() << "Démarrage des transmissions";
        if( bt_Transmission->isChecked() ) {
     
            m_RS_Tools->setRunning( true );
     
            // Mise en place de la réception des trames
            if( threadReception == Q_NULLPTR ) {
                threadReception = new Thread_Exec();
            }
            m_RS_Tools->moveToThread(threadReception);
            m_RS_Tools->connect(threadReception, SIGNAL(started()), m_RS_Tools, SLOT(receptionTrame()), Qt::DirectConnection );
            threadReception->connect( m_RS_Tools, SIGNAL(finished()), SLOT(quit() ), Qt::DirectConnection );
     
     
            // Mise en place de l'emission des trames
            if( threadEmission == Q_NULLPTR ) {
                threadEmission = new Thread_Exec();
            }
            m_RS_Tools->moveToThread(threadEmission);
            m_RS_Tools->connect(threadEmission, SIGNAL(started()), m_RS_Tools, SLOT(initEnvoiTrame()), Qt::DirectConnection );
            m_RS_Tools->connect(threadEmission, SIGNAL(finished() ), m_RS_Tools, SLOT(initEnvoiTrame()), Qt::DirectConnection );
            threadEmission->connect( m_RS_Tools, SIGNAL(finished() ), SLOT( quit() ), Qt::DirectConnection );
     
     
     
            // On démarre le tout
            threadReception->start();
            threadEmission->start();
     
        } else {
             m_RS_Tools->setRunning( false );
        }
     
    }
    RS_Tools.h
    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
    class RS_Tools : public QSerialPort
    {
        Q_OBJECT
     
        bool m_Running;
        QTimer* timerEmission = (QTimer*)(Q_NULLPTR);
     
    public:
        RS_Tools();
        ~RS_Tools();
     
        void setRunning(const bool running);
     
    public slots:
        void initPort(const bool checked);
        void initEnvoiTrame();
        void emissionTrame();
        void receptionTrame();
     
    signals:
        void trameRecue( const QByteArray* data );
        void trameEnvoyee( const QByteArray* data );
        void finished();
     
    };
    RS_Tools.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
    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
    94
    95
    96
    97
    98
    RS_Tools::RS_Tools()
        : m_Running(false)
    {
     
    }
     
    RS_Tools::~RS_Tools()
    {
     
    }
     
    void RS_Tools::setRunning(const bool running)
    {
        qDebug() << "Running = " << running;
        m_Running = running;
    }
     
    void RS_Tools::initPort(const bool checked )
    {
        qDebug() << "Initialisation du port COM";
        setPortName( QSerialPortInfo::availablePorts().first().portName() );
        setBaudRate( QSerialPort::Baud9600 );
        setDataBits( QSerialPort::Data8 );
        setParity( QSerialPort::NoParity );
        setStopBits( QSerialPort::OneStop );
        setFlowControl( QSerialPort::NoFlowControl );
     
        if( checked )
        {
            if( !open( QIODevice::ReadWrite ))
            {
                qDebug() << "Le port COM n'a pas pu être ouvert";
                QMessageBox::critical(Q_NULLPTR, "Ouverture port COM", QObject::tr("Le port %1 n'a pas pu être ouvert").arg( portName() ));
            } else {
                qDebug() << "Le port COM a été ouvert";
                QMessageBox::information(Q_NULLPTR, "Ouverture port COM", QObject::tr("Le port %1 a pu être ouvert").arg( portName() ));
            }
        } else {
            close();
            qDebug() << "Le port est fermé";
        }
     
    }
     
    void RS_Tools::initEnvoiTrame( )
    {
        qDebug() << "Demarrage init envoi trame";
        if( m_Running ) {
            if( timerEmission == Q_NULLPTR ) {
                timerEmission = new QTimer();
                connect(timerEmission, SIGNAL(timeout()), this, SLOT(emissionTrame()));
            }
            timerEmission->start();
            qDebug() << "Timer mis en route";
        } else {
            if( timerEmission != Q_NULLPTR ) {
                if ( timerEmission->isActive() ) {
                    timerEmission->stop();
                    qDebug() << "Arret du timer des emissions";
                }
            }
        }
    }
     
     
    void RS_Tools::emissionTrame()
    {
        if( m_Running ) {
            QString tmpData = QString("Test des datas envoyees\r");
            QByteArray* data = new QByteArray(tmpData.toStdString().c_str());
     
            write(data->data(), data->size());
     
            emit trameEnvoyee( data );
        } else {
            emit finished();
        }
    }
     
     
    void RS_Tools::receptionTrame()
    {
        while( m_Running ) {
            char tmpData[64];
            qstrncpy(tmpData, 0, 64);
            QByteArray* data = new QByteArray();
     
            waitForReadyRead();
            read( tmpData, 64 );
     
            data->append(tmpData);
     
            emit trameRecue( data );
            qDebug() << "Data reçue : " << *data;
        }
     
        emit finished();
    }
    et enfin le Thread_Exec.h tout bete
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    class Thread_Exec : public QThread
    {
    protected:
        void run() { exec(); }
    };

  2. #2
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2011
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 38
    Points : 21
    Points
    21
    Par défaut
    Personne pour me débloquer !!!

    Bon en attendant, j'essaie des choses comme :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
     
            // Mise en place de l'emission des trames
            if( threadEmission == Q_NULLPTR ) {
                threadEmission = new Thread_Exec();
            }
            threadEmission->create( &(m_RS_Tools->initEnvoiTrame()) );
    //        m_RS_Tools->moveToThread(threadEmission);
    //        m_RS_Tools->connect(threadEmission, SIGNAL(started()), m_RS_Tools, SLOT(initEnvoiTrame()), Qt::DirectConnection );
            m_RS_Tools->connect(threadEmission, SIGNAL(finished() ), m_RS_Tools, SLOT(initEnvoiTrame()), Qt::DirectConnection );
            threadEmission->connect( m_RS_Tools, SIGNAL(finished() ), SLOT( quit() ), Qt::DirectConnection );
     
            threadEmission->start();
    là, ça me donne à la compilation :
    ../Test_Timer/mainwindow.cpp: In member function ‘void MainWindow::demarrerTransmission()’:
    ../Test_Timer/mainwindow.cpp:59:63: error: lvalue required as unary ‘&’ operand
    threadEmission->create( &(m_RS_Tools->initEnvoiTrame()) );
    __ ^
    la doc donne comme signature :
    QThread *QThread::create(Function &&f)
    Je n'ai apparement pas compris ce "&&f".
    Je ne sais pas comment gérer çà ...

    Merci de votre aide

  3. #3
    Expert éminent
    Homme Profil pro
    Ingénieur développement matériel électronique
    Inscrit en
    Décembre 2015
    Messages
    1 565
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 61
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Ingénieur développement matériel électronique
    Secteur : High Tech - Électronique et micro-électronique

    Informations forums :
    Inscription : Décembre 2015
    Messages : 1 565
    Points : 7 648
    Points
    7 648
    Par défaut
    Bonjour,

    La fonction qui correspond à ton cas serait plutôt QThread *QThread::create(Function &&f, Args &&... args).
    Ça donnerait plutôt: threadEmission->create( &RS_Tools::initEnvoiTrame , m_RS_Tools );. Car le thread a besoin de connaitre à la fois l'objet et sa fonction associée. je ne connais pas Qt donc peut-être qu'il s'attend à autre chose.

    Le && permet la plupart du temps de définir une référence à un temporaire (r-value-reference), mais ici on est dans le cas où il s'agit plutôt d'une forward-reference. C'est un moyen de récupérer le type exact des paramètres transmis qui peuvent être indifféremment :
    - une l-value-reference (les références à une l-value, celles que tu dois connaître et qui s’écrivent avec un simple &),
    - une r-value-reference (celles qui s'écrivent avec le double &&).

  4. #4
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2011
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 38
    Points : 21
    Points
    21
    Par défaut
    Bonjour dalfab

    Merci de me donner des indications.

    J'ai fait la manip et j'ai comme erreur :
    /dev/Test_Timer/mainwindow.cpp:59: erreur : no matching member function for call to 'create'
    et à la compilation
    ../Test_Timer/mainwindow.cpp: In member function ‘void MainWindow::demarrerTransmission()’:
    ../Test_Timer/mainwindow.cpp:59:72: error: no matching function for call to ‘Thread_Exec::create(void (RS_Tools::*)(), RS_Tools*&)’
    threadEmission->create( &RS_Tools::initEnvoiTrame , m_RS_Tools );
    ^
    In file included from ../../../Qt5.14.2/5.14.2/gcc_64/include/QtCore/QThread:1:0,
    from ../Test_Timer/mainwindow.h:8,
    from ../Test_Timer/mainwindow.cpp:1:
    ../../../Qt5.14.2/5.14.2/gcc_64/include/QtCore/qthread.h:127:21: note: candidate: template<class Function> static QThread* QThread::create(Function&&)
    static QThread *create(Function &&f);
    ^~~~~~
    ../../../Qt5.14.2/5.14.2/gcc_64/include/QtCore/qthread.h:127:21: note: template argument deduction/substitution failed:
    ../Test_Timer/mainwindow.cpp:59:72: note: candidate expects 1 argument, 2 provided
    threadEmission->create( &RS_Tools::initEnvoiTrame , m_RS_Tools );
    ^
    Ce que je comprend donc, c'est qu'il faudrait que "initEnvoiTrame" soit static ?

    J'ai également le "receptionTrame" à faire avec la même méthode. Cela revient à mettre la presque totalité du code en static !!!!

  5. #5
    Membre à l'essai
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Août 2011
    Messages
    38
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Août 2011
    Messages : 38
    Points : 21
    Points
    21
    Par défaut
    En plus de la bonne commande, il faut mettre c++17 dans le .pro

    Cela compile mais j'ai d'autres soucis.
    A voir si c'est lié.

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

Discussions similaires

  1. Réponses: 3
    Dernier message: 12/11/2018, 13h32
  2. Opération mathématique entre deux Threads
    Par rvzip64 dans le forum Langage
    Réponses: 11
    Dernier message: 13/06/2005, 11h58
  3. [CVS] gérer deux CVS pour un projet
    Par tmcgrady dans le forum Eclipse Java
    Réponses: 3
    Dernier message: 02/03/2005, 15h48
  4. Communication entre deux Threads
    Par rvzip64 dans le forum Langage
    Réponses: 13
    Dernier message: 28/01/2005, 09h14
  5. [Jacob] gérer deux versions de Word installées
    Par difdaf dans le forum Documents
    Réponses: 2
    Dernier message: 16/07/2004, 18h32

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