Domanda

Che cosa significa per spostare un oggetto da un thread a un altro in Qt usando moveToThread? Tutto sembra funzionare anche prima di utilizzare moveToThread, che sposta l'oggetto da un filo (filo GUI) per un altro filo (lavorato) e Qt:. Collegare chiamate alloggiamento dell'unità oggetto

C'è qualche differenza a causa di dove l'oggetto vite, filo GUI o il thread di lavoro?

EDIT: Ho fatto un piccolo programma, ma io non capisco come QThread lavora insieme con il segnale e la funzione di slot, le sarei grato se potesse spiegare che cosa è l'uso di moveToThread con l'esempio

#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);
 }
È stato utile?

Soluzione

Date un'occhiata a Segnali e slot attraverso fili . Se si usa sempre segnali e slot per comunicare con il thread di lavoro, Qt gestisce il moveToThread per voi se è necessario e si utilizza la connessione corretta.

Modifica: Direi l'autore dell'articolo è stato vedere il suo problema da quando stava chiamando inizio nel costruttore prima che il thread è stato effettivamente creato. In altre parole, non si fidano codice di terze parti ciecamente.

Edit: In risposta al tuo commento, guardare il Mandelbrot esempio, sotto l'intestazione MandelbrotWidget Class Implementation:

  

Con connessioni in coda, Qt deve memorizzare una copia degli argomenti che sono stati passati al segnale in modo che possa passare allo slot seguito. Qt sa come prendere di copia di molti tipi C ++ e Qt, ma QImage non è uno di questi. Dobbiamo quindi chiamare la funzione template qRegisterMetaType () prima di poter usare QImage come parametro connessioni in coda.

Credo che questo sia un po 'datato, ecco il validi tipi di meta . Dal momento che i segnali e gli slot in tutta discussioni utilizzano connessioni in coda, non si dovrebbe avere a che fare il moveToThread chiama in molti casi.

Modifica: Cercherò di spiegare le cose con un esempio simile:

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

Esempio di output dopo cliccando sul pulsante:

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

Come si può vedere, il filo corsa è diverso da quello del filo GUI principale. Inoltre, anche se si passa un riferimento const ad un QString, dal momento che attraversa i confini della discussione lo copia. Ho con forza vi incoraggio a leggere Fili e QObject .

Altri suggerimenti

  1. Il metodo QThread::start() crea il filo e chiama l'implementazione run(). Se si desidera gestire eventi o segnali ricevuti sul filo devi chiamare QThread::exec() all'interno della vostra implementazione run(). Non si dovrebbe mai chiamare run() in modo esplicito e non si dovrebbe mai chiamare exec() al di fuori della run().

  2. Il filo proprietario fa la differenza solo quando uno slot è collegato ad un segnale con il tipo di connessione diverso Qt::DirectConnection. Poi Qt farà in modo che la fessura corre sul filo proprietario, ma per che il thread proprietario deve essere in esecuzione di un ciclo di eventi con QThread::exec(). In questo caso chiamare myObj.moveToThread(myThread) farà in modo che myObj slot eseguiti sul myThread thread.

  3. L'oggetto thread appartiene al thread in cui è stato creato, non sul filo che gestisce (e dove il metodo run verrà eseguito). Così, quando si collega un segnale di slot di un oggetto filo, quello slot verrà eseguito nel thread in cui l'oggetto thread è stato creato a meno che non si chiama moveToThread().

Quando si sposta un oggetto tra i thread, a decidere quale ciclo di eventi a cui appartiene. Quando si effettua connessioni all'interno di un filo, il codice di segnalazione chiama direttamente ciascuna delle asole (dover attendere la fine dell'operazione). Segnalazione di là dei confini della discussione la chiamata segnale sul ciclo di eventi, lasciando filo dello slot effettuare la chiamata allo slot quando è pronto.

Effettuare chiamate dirette tra le discussioni si richiede di fare in modo che le funzioni sono rientranti. È inoltre necessario assicurarsi di proteggere i dati utilizzando i mutex o semafori e allo stesso tempo evitare condizioni di gara.

In questo articolo, credo che il ritardo è dovuto che la comunicazione sia diretta, vale a dire non a tutti trattati nei precedenti (ma ho scremato solo il testo).

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

oggetto thread viene creato e l'oggetto thread viene spostato lo stesso filo. I segnali sono ora tra fili e tipo di connessione sono entrambi coda e funziona come previsto.

alcuni oggetti solo può essere utilizzato sul filo del proprietario. ad esempio, se si crea e oggetto socket in un thread e si desidera inviare i dati e recv in un altro thread è is'nt possibile. quindi una soluzione è quella di spostare l'oggetto da un thread all'altro ed operare su di esso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top