Frage

Was bedeutet es, ein Objekt von einem Thread zu einem anderen in Qt moveToThread zu bewegen? Alles scheint zu arbeiten, noch bevor mit moveToThread, die das Objekt von einem Thread (GUI-Thread) bewegt sich auf einem anderen Thread (gearbeitet) und Qt. Connect Anrufen den entsprechenden Steckplatz am Objekt

Gibt es einen Unterschied, da, wo das Objekt lebt, GUI-Thread oder der Arbeiter-Thread?

EDIT: Ich hatte ein kleines Programm, aber ich verstehe nicht, wie QThread zusammen mit Signal arbeitet und Slot-Funktion, würde ich mich freuen, wenn Sie könnte erklären, was die Verwendung von moveToThread mit dem Beispiel ist

#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);
 }
War es hilfreich?

Lösung

Hier finden Sie aktuelle Signale und Schlitze über Threads . Wenn Sie immer Signale und Slots verwenden, um mit dem Arbeitsthread zu kommunizieren, behandelt Qt die moveToThread für Sie, wenn es gebraucht wird und verwendeten Sie die richtige Verbindung.

Edit: Ich würde die Sache des Autors erraten sah sein Problem, da er Anfang im Konstruktor aufrufen, bevor der Thread tatsächlich erstellt wurde. Mit anderen Worten, nicht vertrauen Code von Drittanbietern blind.

Edit: Als Antwort auf Ihren Kommentar, Blick auf die Mandelbrots Beispiel unter dem MandelbrotWidget Class Implementation Header:

  

Mit der Warteschlange Verbindungen müssen Qt eine Kopie der Argumente speichern, die auf das Signal weitergegeben wurden, so dass sie sie in den Schlitz später passieren kann. Qt weiß, wie die Kopie vieler C ++ zu nehmen und Qt-Typen, aber QImage ist nicht einer von ihnen. Wir müssen deshalb die Template-Funktion qRegisterMetaType () aufrufen, bevor wir QImage als Parameter in der Warteschlange Verbindungen nutzen können.

Ich glaube, das etwas veraltet ist, sind hier die gültig Meta-Typen . Da Signale und Slots über Threads Verbindungen der Warteschlange verwenden, sollten Sie nicht die moveToThread Anrufe in den meisten Fällen zu tun haben.

Edit: Ich werde versuchen, die Dinge mit einem ähnlichen Beispiel zu erklären:

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

Beispiel für die Ausgabe nach dem Klicken auf die Taste:

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

Wie Sie sehen können, die Laufgewinde ist anders als die Haupt GUI-Thread. Auch, obwohl Sie eine konstante Referenz auf ein QString passieren, da es Thread Grenzen kopiert es überquert. I stark ermutigen Sie Themen und QObject .

Andere Tipps

  1. Die QThread::start() Methode erstellt den Faden und ruft Ihre run() Umsetzung. Wenn Sie Ereignisse oder empfangenen Signale auf den Faden zu handhaben wollen, müssen Sie Anruf QThread::exec() innen Ihre run() Implementierung. Sie sollten nie run() explizit aufrufen und Sie sollten nie exec() außerhalb von run().

  2. rufen
  3. Der Eigentümer Thread einen Unterschied macht, wenn nur ein Schlitz in ein Signal mit der Verbindungsart außer Qt::DirectConnection verbunden ist. Dann wird Qt sicherzustellen, dass der Schlitz auf dem Eigentümer Thread läuft, aber für, dass der Eigentümer Thread muss eine Ereignisschleife mit QThread::exec() laufen. In diesem Fall ruft myObj.moveToThread(myThread) wird feststellen, dass myObj Schlitze läuft auf dem Gewinde myThread gewährleisten.

  4. Das Thread-Objekt gehört den Thread, in dem es erstellt wurde, nicht auf dem Faden, den er verwaltet (und wo die run-Methode wird ausgeführt). Also, wenn Sie ein Signal an ein Thread-Objekt des Slot verbinden, dass Slot wird in dem Thread ausgeführt werden, wo das Thread-Objekt erstellt wurde, es sei denn, Sie moveToThread() nennen.

Wenn Sie ein Objekt zwischen Threads zu bewegen, entscheiden Sie, welche Ereignisschleife es gehört. Wenn Verbindungen in einem Thread zu machen, ruft der Signalisierungscode direkt jeweils einen der Schlitze (mit warten, dass sie bis zum Ende). Signalisierung über Faden Grenzen setzt das Signal Anruf auf der Ereignisschleife, die Slot Thread den Anruf an den Schlitz machen zu lassen, wenn Sie fertig.

machen direkte Anrufe zwischen Threads müssen Sie sicherstellen, dass Ihre Funktionen einspringenden sind. Sie müssen auch sicherstellen, dass Ihre Daten mit Mutexe oder Semaphore und zugleich vermeiden Rennbedingungen zu schützen.

In dem Artikel, ich denke, dass die Verzögerung aufgrund des Anruf ist direkt, das heißt überhaupt nicht im Hintergrund verarbeitet (aber ich abgeschöpft nur den Text).

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

New Thread-Objekt wird erstellt und das Thread-Objekt wird auf den gleichen Thread bewegt. Die Signale sind jetzt über Threads und Verbindungstyp beide Warteschlange sind und es funktioniert wie erwartet.

nur einige Objekte können auf den Eigentümer Thread verwendet werden. wenn Sie zum Beispiel erstellen und Socket-Objekt in einem Thread und Sie möchten senden und recv Daten in einem anderen Thread is'nt es möglich. Daher ist eine Lösung, Ihr Objekt von einem Thread zum anderen und arbeiten auf sie zu bewegen.

scroll top