Pergunta

O que significa para mover um objeto de um segmento para outro em Qt usando moveToThread?Tudo parece funcionar mesmo antes de utilizar moveToThread, o que move o objeto a partir de uma thread (thread da GUI) para uma outra thread ( trabalhou) e Qt:ligue chama o espaço apropriado no objeto.

Existe alguma diferença, porque de onde o objeto vidas, thread da GUI ou o thread de trabalho?

EDITAR:Eu fiz um pequeno programa, mas eu não entendo como QThread funciona junto com o Sinal e o slot função, eu agradeceria se você pudesse explicar o que é o uso de moveToThread com o exemplo

#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);
 }
Foi útil?

Solução

Dê uma olhada no Sinais e slots em threads.Se você sempre usar sinais e slots para se comunicar com o thread de trabalho, Qt trata o moveToThread para você, se é necessário e tiver usado a conexão correta.

Editar:Eu acho que o artigo do autor era de ver o seu problema, já que ele estava ligando para iniciar o construtor, antes da thread foi realmente criado.Em outras palavras, não confie código de terceiros cegamente.

Editar:Em resposta ao seu comentário, olhar para o Mandelbrot exemplo, sob a MandelbrotWidget Class Implementation cabeçalho:

Com fila de espera de ligações, Qt deve armazenar uma cópia dos argumentos que foram passados para o sinal para que possa passá-los para o slot mais tarde.Qt sabe como tirar de cópia de muitos C++ e Qt tipos, mas QImage não é um deles.Devemos, portanto, chamar a função de modelo qRegisterMetaType() antes de podermos usar QImage como parâmetro na fila de conexões.

Eu acredito que isso é um pouco desatualizado, aqui estão os válido meta tipos de.Desde sinais e slots de toda utilizam threads na fila de conexões, você não deve ter para fazer o moveToThread chamadas na maioria dos casos.

Editar:Vou tentar explicar com um exemplo semelhante:

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();
}

Exemplo de saída depois de clicar no botão:

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

Como você pode ver, a linha é diferente do que o principal thread da GUI.Além disso, mesmo que você passe uma constante referência a uma QString, uma vez que ele cruza limites de thread copia-lo.Eu fortemente encorajamos você a ler Linhas e QObject.

Outras dicas

  1. o QThread::start() o método cria o tópico e chama seu run() implementação. Se você deseja lidar com eventos ou sinais recebidos no tópico que você deve ligar QThread::exec() lado de dentro sua run() implementação. Você nunca deve ligar run() explicitamente e você nunca deve ligar exec() fora de run().

  2. O fio do proprietário faz a diferença apenas quando um slot é conectado a um sinal com o tipo de conexão que não Qt::DirectConnection. Em seguida, o QT garantirá que o slot funcione no tópico do proprietário, mas para isso o tópico do proprietário deve estar executando um loop de evento com QThread::exec(). Neste caso, chamando myObj.moveToThread(myThread) garantirá isso myObj slots funcionam no tópico myThread.

  3. O objeto Thread pertence ao encadeamento onde foi criado, não no encadeamento que ele gerencia (e onde o método de execução será executado). Então, quando você conecta um sinal ao slot de um objeto de rosca, esse slot será executado no fio onde o objeto de thread foi criado, a menos que você ligue moveToThread().

Ao mover um objeto entre os threads, você decide qual loop de evento ele pertence. Ao fazer conexões dentro de um encadeamento, o código de sinalização chama diretamente cada um dos slots (precisando esperar que eles terminem). A sinalização através dos limites do encadeamento coloca a chamada do sinal no loop do evento, deixando o fio do slot fazer a chamada para o slot quando estiver pronta.

Fazer chamadas diretas entre os threads exige que você certifique -se de que suas funções sejam reentrantes. Você também deve proteger seus dados usando mutexes ou semáforos e, ao mesmo tempo, evite as condições de corrida.

No artigo, acho que o atraso se deve ao fato de a chamada ser direta, ou seja, nem um pouco processada em segundo plano (mas eu apenas deslizei o texto).

#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();
 }

O novo objeto Thread é criado e o objeto Thread é movido para o mesmo thread. Agora, os sinais estão entre threads e o tipo de conexão são a fila e funciona como esperado.

alguns objetos só podem ser utilizados no segmento proprietário.por exemplo, se você criar e tomada de objeto em uma thread e você deseja utilizar para enviar e receber dados em outro thread é nt possível.portanto, uma solução é mover o seu objeto a partir de um segmento para o outro e de operar sobre ele.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top