Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Qt signaling across threads, one is GUI thread?

What does it mean to move a object from one thread to another in Qt using moveToThread? Everything seems to work even before using moveToThread, which moves the object from one thread (GUI thread) to a another thread ( worked) and Qt:connect calls the appropriate slot on object.

Is there any difference because of where the object lives, GUI thread or the worker thread?

EDIT: I made a small program, but I don't understand how QThread works along with Signal and slot function, I would appreciate if you could explain what is the use of moveToThread with the example

#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);  } 
like image 704
Passionate programmer Avatar asked Jan 18 '10 13:01

Passionate programmer


People also ask

How signal and slot works in Qt?

In Qt, we have an alternative to the callback technique: We use signals and slots. A signal is emitted when a particular event occurs. Qt's widgets have many predefined signals, but we can always subclass widgets to add our own signals to them. A slot is a function that is called in response to a particular signal.

Are Qt signals thread safe?

It is generally unsafe to provide slots in your QThread subclass, unless you protect the member variables with a mutex. On the other hand, you can safely emit signals from your QThread::run() implementation, because signal emission is thread-safe.

Is Qt multithreaded?

Qt offers many classes and functions for working with threads. Below are four different approaches that Qt programmers can use to implement multithreaded applications.

What is thread in Qt?

A QThread object manages one thread of control within the program. QThreads begin executing in run(). By default, run() starts the event loop by calling exec() and runs a Qt event loop inside the thread. You can use worker objects by moving them to the thread using QObject::moveToThread().


1 Answers

Take a look at Signals and slots across threads. If you always use signals and slots to communicate with the worker thread, Qt handles the moveToThread for you if it's needed and you used the correct connection.

Edit: I would guess the article's author was seeing his problem since he was calling start in the constructor before the thread was actually created. In other words, don't trust third-party code blindly.

Edit: In response to your comment, look at the Mandelbrot example, under the MandelbrotWidget Class Implementation header:

With queued connections, Qt must store a copy of the arguments that were passed to the signal so that it can pass them to the slot later on. Qt knows how to take of copy of many C++ and Qt types, but QImage isn't one of them. We must therefore call the template function qRegisterMetaType() before we can use QImage as parameter in queued connections.

I believe this is slightly outdated, here are the valid meta types. Since signals and slots across threads use queued connections, you should not have to do the moveToThread calls in most cases.

Edit: I will try to explain things with a similar example:

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

Sample output after clicking button:

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

As you can see, the run thread is different than the main GUI thread. Also, even though you pass a const reference to a QString, since it crosses thread boundaries it copies it. I strongly encourage you to read Threads and QObject.

like image 70
Adam W Avatar answered Oct 14 '22 21:10

Adam W