Question

Qu'est-ce que cela signifie pour déplacer un objet d'un fil à l'autre dans Qt en utilisant moveToThread? Tout semble fonctionner même avant d'utiliser moveToThread, qui déplace l'objet à partir d'un fil (fil GUI) à un autre fil (de travail) et Qt. Connecter les appels l'emplacement approprié sur l'objet

Y at-il une différence en raison de l'endroit où vit objet, fil de l'interface graphique ou le thread de travail?

EDIT: J'ai fait un petit programme, mais je ne comprends pas comment fonctionne QThread avec signal et la fonction de l'emplacement, je vous serais reconnaissant si vous pouviez expliquer ce qui est de l'utilisation moveToThread avec l'exemple

#include <QtGui/QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QString>
#include "mythread.h"
//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget w;
    QHBoxLayout * pH = new QHBoxLayout(&w);
    QPushButton * pushButton = new QPushButton("asdad");
    QLineEdit * lineEdit = new QLineEdit("AAA");
    pH->addWidget(pushButton);
    pH->addWidget(lineEdit);
    w.setLayout(pH);
    w.show();
    MyThread thread;
    qDebug("Thread id %d",(int)QThread::currentThreadId());
    QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun())) ;
    QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString)));
    return a.exec();
}

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QMutex>

class MyThread : public QThread
{
    Q_OBJECT
public:
    MyThread();
public slots:
    void callRun();
    void run();
 signals:
    void signalGUI(QString);
private:
    QMutex mutex;

};

#endif // MYTHREAD_H


#include "mythread.h"
#include <QDebug>
#include <QString>
#include <QMutexLocker>

MyThread::MyThread()
{
}
 void MyThread::callRun()
 {

     qDebug("in thread");
    if(!isRunning())
     {
        this->start(LowestPriority);
        exec();
    }
    else
    {
        run();
    }

 }
 void MyThread::run()
 {
     QMutexLocker fn_scope(&mutex);
     static int a = 0;
    ++a;
     qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
     this->sleep(3);
     static QString number;
     QString temp;
     number += temp.setNum(a);
     emit signalGUI(number);
 }
Était-ce utile?

La solution

Jetez un oeil à signaux et des fentes à travers des fils . Si vous utilisez toujours des signaux et slots pour communiquer avec le thread de travail, gère Qt le moveToThread pour vous si cela est nécessaire et vous avez utilisé la connexion correcte.

Edit: Je suppose que voyait son problème depuis qu'il appelle début dans le constructeur avant que le thread a été effectivement créé l'auteur de l'article. En d'autres termes, ne faites pas confiance code tiers à l'aveuglette.

Edit: En réponse à votre commentaire, regardez la l'exemple Mandelbrot de, sous l'en-tête MandelbrotWidget Class Implementation:

  

Avec les connexions en file d'attente, Qt doit stocker une copie des arguments qui ont été transmis au signal afin qu'il puisse les transmettre à la fente plus tard. Qt sait comment prendre la copie de nombreux types C ++ et Qt, mais QImage n'est pas un d'entre eux. Il faut donc appeler le qRegisterMetaType () fonction de modèle avant de pouvoir utiliser QImage comme paramètre dans les connexions en file d'attente.

Je crois que ce qui est légèrement dépassé, voici la valides les méta-types . Les signaux et les fentes dans les threads utilisent des connexions en file d'attente, vous ne devriez pas avoir à faire le moveToThread appelle dans la plupart des cas.

Edit: Je vais essayer d'expliquer les choses avec un exemple similaire:

mythread.h:

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QMutex>

class MyThread : public QThread
{
   Q_OBJECT

protected:
   virtual void run();

signals:
   void signalGUI(QString);
};

#endif // MYTHREAD_H

mythread.cpp:

#include "mythread.h"
#include <QString>

void MyThread::run()
{
   qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
   static int run = 0;
   QString temp = QString("Run: %1").arg(run++);
   qDebug("String address inside run %p", &temp);
   emit signalGUI(temp);
}

mylineedit.h

#ifndef MYLINEEDIT_H
#define MYLINEEDIT_H

#include <QLineEdit>

class MyLineEdit : public QLineEdit
{
Q_OBJECT
public:
    explicit MyLineEdit(QWidget *parent = 0);

public slots:
    void setText(const QString &string);

};

#endif // MYLINEEDIT_H

mylineedit.cpp

#include "mylineedit.h"
#include <QThread>

MyLineEdit::MyLineEdit(QWidget *parent) :
    QLineEdit(parent)
{
}

void MyLineEdit::setText(const QString &string)
{
   qDebug("Thread id inside setText %d",(int)QThread::currentThreadId());
   qDebug("String address inside setText %p\n", &string);
   QLineEdit::setText(string);
}

main.cpp:

#include <QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include "mythread.h"
#include "mylineedit.h"

//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
   QApplication a(argc, argv);
   QWidget w;
   QHBoxLayout * pH = new QHBoxLayout(&w);
   QPushButton * pushButton = new QPushButton("Run Thread", &w);
   MyLineEdit * lineEdit = new MyLineEdit(&w);

   pH->addWidget(pushButton);
   pH->addWidget(lineEdit);
   w.show();

   MyThread thread;
   qDebug("Thread id %d",(int)QThread::currentThreadId());
   QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(start())) ;
   QObject::connect(&thread,SIGNAL(signalGUI(const QString&)),lineEdit,SLOT(setText(const QString&)));
   return a.exec();
}

Exemple de sortie après cliquant sur le bouton:

Thread id 1088110320
Thread id inside run 1093176208
String address inside run 0x41288350
Thread id inside setText 1088110320
String address inside setText 0x974af58

Comme vous pouvez le voir, le fil d'exécution est différent du fil de l'interface graphique principale. En outre, même si vous passez une référence const à un QString, car il traverse les frontières de fil il copie il. I fortement vous encourager à lire Fils et QObject .

Autres conseils

  1. La méthode QThread::start() crée le fil et appelle l'implémentation de run(). Si vous voulez gérer les événements ou les signaux reçus sur le fil que vous devez appeler QThread::exec() dans votre implémentation de run(). Vous ne devriez jamais appeler explicitement run() et vous ne devriez jamais appeler exec() en dehors de run().

  2. Le fil de propriétaire fait une différence seulement quand une fente est reliée à un signal avec le type de connexion autre que Qt::DirectConnection. Ensuite, Qt veillera à ce que la fente fonctionne sur le thread propriétaire, mais pour que le thread propriétaire doit exécuter une boucle d'événement avec QThread::exec(). Dans ce cas, l'appel myObj.moveToThread(myThread) veillera à ce que les fentes myObj fonctionnent sur le fil myThread.

  3. L'objet de fil appartient au fil où il a été créé, non pas sur le fil qu'il gère (et où la méthode d'exécution fonctionnera). Donc, lorsque vous vous connectez un signal à l'emplacement d'un objet de fil, cette fente se déroulera dans le thread où l'objet de fil a été créé à moins que vous appelez moveToThread().

Lors du déplacement d'un objet entre les threads, vous décidez boucle événement auquel il appartient. Lors des connexions à l'intérieur d'un fil, le code de signalisation appelle directement chacune des fentes (avoir à attendre pour eux à la fin). Signalisation à travers les frontières de fil met l'appel de signal sur la boucle d'événements, laissant le fil de la fente faire l'appel à la fente lorsque vous êtes prêt.

Faire des appels directs entre les threads vous devez vous assurer que vos fonctions sont rentrante. Vous devez également vous assurer de protéger vos données en utilisant les mutex ou sémaphores et en même temps d'éviter les conditions de course.

Dans l'article, je suppose que le retard est dû à l'appel étant directe, à savoir pas du tout traité en arrière-plan (mais je qu'effleurer le texte).

#include <QtGui/QApplication>
#include <QPushButton>
#include <QHBoxLayout>
#include <QLineEdit>
#include <QString>
#include "mythread.h"
//GUI calls a thread to do some job and sub update the text box once it is done
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QWidget w;
    QHBoxLayout * pH = new QHBoxLayout(&w);
    QPushButton * pushButton = new QPushButton("asdad");
    QLineEdit * lineEdit = new QLineEdit("AAA");
    pH->addWidget(pushButton);
    pH->addWidget(lineEdit);
    w.setLayout(pH);
    w.show();
    MyThread thread;
    thread.moveToThread(&thread);
    thread.start();
    qDebug("Thread id %d",(int)QThread::currentThreadId());
    QObject::connect(pushButton,SIGNAL(clicked()),&thread,SLOT(callRun()),Qt::QueuedConnection) ;
    QObject::connect(&thread,SIGNAL(signalGUI(QString)),lineEdit,SLOT(setText(QString)),Qt::DirectConnection);
    return a.exec();
}

#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QMutex>

class MyThread : public QThread
{
    Q_OBJECT
public:
    MyThread();
public slots:
    void callRun();
    void run();
 signals:
    void signalGUI(QString);
private:
    QMutex mutex;

};

#endif // MYTHREAD_H
#include "mythread.h"
#include <QDebug>
#include <QString>
#include <QMutexLocker>

MyThread::MyThread()
{
}
 void MyThread::callRun()
 {
     QMutexLocker fn_scope(&mutex);
     static int a = 0;
    ++a;
     qDebug("Thread id inside run %d",(int)QThread::currentThreadId());
     this->sleep(3);
     static QString number;
     QString temp;
     number += temp.setNum(a);
     emit signalGUI(number);

 }
 void MyThread::run()
 {
    exec();
 }

Nouvel objet de thread est créé et l'objet de fil est déplacé vers le même fil. Les signaux sont maintenant entre les threads et le type de connexion sont à la fois la file d'attente et il fonctionne comme prévu.

certains objets ne peuvent être utilisés sur le thread propriétaire. par exemple, si vous créez et objet socket dans un thread et que vous voulez envoyer les données à recv dans un autre thread, il is'nt possible. donc une solution consiste à déplacer votre objet d'un fil à l'autre et l'opérer.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top