Search code examples
c++multithreadingqtsignals-slotsqthread

How to signal a slot in another thread in Qt


I have written a simple signal slot application using Qt. I want to send a signal to another thread that is runs out of the main thread.

Here is my code:

class Thread1 : public QThread
{
    Q_OBJECT


    void run()
    {
        exec();
    }
public:
    Thread1(QObject* parent);

public slots:
    void a()
    {
        qInfo()<<QThread::currentThreadId();
    }
};
class Object : public QObject
{
    Q_OBJECT
public:
    Object(){}
    void start()
    {
        qInfo()<<QThread::currentThreadId();
        Thread1* thread = new Thread1(this);
        connect(this,SIGNAL(a()),thread,SLOT(a()));
        thread->start();
        emit a();
    }

signals:
    void a();
};

But it returns:

0x7f9851c988c0
0x7f9851c988c0

How can I call a signal that outputs another threadID?


Solution

  • You've got it backwards. A QThread is a thread handle, not a thread itself. If you want to run something in another thread, it belongs in a plain QObject that you move to a thread. You don't need to derive from QThread at all! You also shouldn't move a QThread's base QObject to the thread itself. What you do is have a handle to the thread live in the thread itself. As soon as the thread finishes, the handle becomes non-functional (a QObject with a null thread()).

    First of all, if all you need is to run some code that runs to completion (e.g. does a calculation) in a worker thread, use the thread pool and QtConcurrent framework. It manages all the threads for you:

    #include <QtConcurrent>
    ...
    QThread::currentThread()->setObjectName("main");
    qDebug() << QThread::currentThread();
    QtConcurrent::run([]{ qDebug() << QThread::currentThread(); }
    

    If you insist on controlling the thread's lifetime yourself, you'd do the following:

    #include <QtCore>
    struct Worker : QObject {
      Q_SLOT void aSlot() { 
        qDebug() << QThread::currentThread(); 
        QThread::currentThread()->quit();
      }
      Q_SIGNAL void aSignal();
      Q_OBJECT
    };
    
    int main(int argc, char ** argv) {
      QCoreApplication app{argc, argv};
      QThread::currentThread()->setObjectName("main");
      QThread thread;
      thread.setObjectName("thread");
      Worker a, b;
      b.moveToThread(&thread);
      thread.start();
      QObject::connect(&a, &Worker::aSignal, &b, &Worker::aSlot);
      emit a.aSignal(); // the signal is emitted from the main thread
      thread.wait();
    }
    

    Finally, note that the QDebug class knows how to output the object's address, class and name (if set) when passed a pointer to a QObject. Thus, you don't need to use QThread::currentThreadId(), the QThread::currentThread() is sufficient - and you can give the threads mnemonic names since they are QObjects, after all.