1

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?

sandwood
  • 2,038
  • 20
  • 38
Matin Lotfaliee
  • 1,745
  • 2
  • 21
  • 43

2 Answers2

9

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.

Kuba hasn't forgotten Monica
  • 95,931
  • 16
  • 151
  • 313
-2

Implement Thread1 constructor like following :

Thread1(QObject* parent) { moveToThread(this); }
Murat Şeker
  • 1,651
  • 1
  • 16
  • 29
  • Yep that did the work. but it needs the parent to be removed. – Matin Lotfaliee Jun 29 '16 at 18:23
  • Why parent needs to be removed ? – Murat Şeker Jun 29 '16 at 18:25
  • It printed out that moveToThread can not be called for a object that has parent. – Matin Lotfaliee Jun 29 '16 at 18:29
  • Parent doesn't need to be removed, only the parent-child relationship. From the documentation : "The child of a QObject must always be created in the thread where the parent was created. This implies, among other things, that you should never pass the QThread object (this) as the parent of an object created in the thread (since the QThread object itself was created in another thread)." Refer to : http://doc.qt.io/qt-5.7/threads-qobject.html – Murat Şeker Jun 29 '16 at 18:36
  • 2
    This works, but is a bad idea because `QThread` is a thread handle. Conceptually, having a handle to a resource within the controlled resource is backwards. – Kuba hasn't forgotten Monica Jun 29 '16 at 20:35