Qt сигнализирует по streamам, один – stream GUI?

Что означает перемещение объекта из одного streamа в другой в Qt с помощью moveToThread? Кажется, что все работает до использования moveToThread, который перемещает объект из одного streamа (stream GUI) в другой stream (работает) и Qt: connect вызывает соответствующий слот на объекте.

Есть ли разница в том, где живет объект, stream GUI или рабочий stream?

EDIT: Я сделал небольшую программу, но я не понимаю, как работает QThread вместе с функцией Signal и slot, я был бы признателен, если бы вы могли объяснить, что такое использование moveToThread с примером

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

    Взгляните на Сигналы и слоты в streamах . Если вы всегда используете сигналы и слоты для связи с рабочим streamом, Qt обрабатывает moveToThread для вас, если это необходимо, и вы использовали правильное соединение.

    Редактировать: я бы предположил, что автор статьи видел свою проблему, так как он вызывал начало в конструкторе до того, как stream был фактически создан. Другими словами, не доверяйте стороннему коду слепо.

    Изменить. В ответ на ваш комментарий просмотрите пример MandelbrotWidget Class Implementation заголовке MandelbrotWidget Class Implementation :

    При подключении по очереди Qt должен хранить копию аргументов, переданных сигналу, чтобы впоследствии передать их в слот. Qt знает, как взять копию многих типов C ++ и Qt, но QImage не является одним из них. Поэтому мы должны вызвать функцию шаблона qRegisterMetaType (), прежде чем мы сможем использовать QImage в качестве параметра в связанных в очереди соединениях.

    Я считаю, что это немного устарело, вот допустимые мета-типы . Поскольку сигналы и слоты в streamах используют очереди в очереди, в большинстве случаев вам не нужно делать вызовы moveToThread.

    Изменить: я попытаюсь объяснить вещи аналогичным примером:

    mythread.h:

     #ifndef MYTHREAD_H #define MYTHREAD_H #include  #include  class MyThread : public QThread { Q_OBJECT protected: virtual void run(); signals: void signalGUI(QString); }; #endif // MYTHREAD_H 

    mythread.cpp:

     #include "mythread.h" #include  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  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  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  #include  #include  #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(); } 

    Пример вывода после нажатия кнопки:

      Тема id 1088110320
     ИД streamа внутри прогона 1093176208
     Строковый адрес внутри пробега 0x41288350
     Идентификатор streamа внутри setText 1088110320
     Строковый адрес внутри setText 0x974af58 

    Как вы можете видеть, stream выполнения отличается от основного streamа графического интерфейса. Кроме того, несмотря на то, что вы передаете ссылку const на QString, поскольку она пересекает границы streamов, она копирует ее. Я настоятельно рекомендую вам прочитать Threads и QObject .

    1. Метод QThread::start() создает stream и вызывает реализацию run() . Если вы хотите обрабатывать события или принимать сигналы в streamе, вы должны вызывать QThread::exec() внутри реализации run() . Вы никогда не должны вызывать run() явно, и вы никогда не должны вызывать exec() вне run() .

    2. Поток владельца имеет значение только тогда, когда слот подключен к сигналу с типом соединения, отличным от Qt::DirectConnection . Затем Qt гарантирует, что слот будет работать в streamе владельца, но для этого stream владельца должен запускать цикл событий с QThread::exec() . В этом случае вызов myObj.moveToThread(myThread) гарантирует, что слоты myObj выполняться в streamе myThread .

    3. Объект нити принадлежит streamу, где он был создан, а не streamу, которым он управляет (и где будет запускаться метод запуска). Поэтому, когда вы подключаете сигнал к слоту объекта streamа, этот слот будет запускаться в streamе, где был создан объект streamа, если вы не вызываете moveToThread() .

    При перемещении объекта между streamами вы определяете, к какому циклу событий он принадлежит. При выполнении соединений внутри streamа код сигнализации напрямую вызывает каждый из слотов (чтобы дождаться их завершения). Сигнализация по границам streamов помещает вызов сигнала в цикл событий, позволяя streamу слота совершать вызов в слот, когда он готов.

    Выполнение прямых вызовов между streamами требует, чтобы ваши функции были повторно введены. Вы также должны обеспечить защиту своих данных с помощью мьютексов или семафоров и в то же время избегать условий гонки.

    В этой статье я полагаю, что задержка связана с прямым вызовом, то есть вовсе не обработанным в фоновом режиме (но я только просматривал текст).

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

    Создается новый объект streamа, и объект streamа перемещается в тот же stream. Сигналы теперь отображаются по streamам, а тип соединения – как очередь, так и работает, как ожидалось.

    некоторые объекты могут использоваться только в streamе владельца. например, если вы создаете и сокет-объект в одном streamе, и вы хотите отправлять и возвращать данные в другой stream, это невозможно. поэтому одно решение – перемещать ваш объект из одного streamа в другой и работать с ним.

    Давайте будем гением компьютера.