2

Simple question: is it possible to detach a QObject from a QThread in order to move it to the main thread?

I use the following code:

QThread *thread = new QThread();

MyObject *object = new MyObject();

object->moveToThread(thread);

thread->start();

And somewhere after I want to move the MyObject instance to the main thread.

object->moveToThread(QApplication::instance()->thread());

I have the following error: QObject::moveToThread: Current thread (0x00000001) is not the object's thread (0x00000002). Cannot move to target thread (0x00000003).

Thanks

Maxbester
  • 2,435
  • 7
  • 42
  • 70

1 Answers1

3

As the official doc says, moveToThread function can not "pull" an object from another thread, it "pushes" an object to another thread.

That's why if you want to change the thread affinity of your object, you should do it in the current object's thread.

I've added a simple example.

Here's Worker class:

class Worker : public QObject
{
    Q_OBJECT
public:
    explicit Worker(QObject *parent = 0);
signals:
    void done();

public slots:
    void doWork();
    void checkThread();

private:
    bool isMainThread();
};

Worker::Worker(QObject *parent) :
    QObject(parent)
{
    qDebug() << __PRETTY_FUNCTION__ 
             << QThread::currentThread() 
             << isMainThread();
}

void Worker::doWork()
{
    qDebug() << __PRETTY_FUNCTION__ 
             << QThread::currentThread() 
             << isMainThread();

    qDebug() << __PRETTY_FUNCTION__ << "Work is done";
    moveToThread(qApp->thread());
    emit done();
}

void Worker::checkThread()
{
    qDebug() << __PRETTY_FUNCTION__ 
             << QThread::currentThread() 
             << isMainThread();
}

bool Worker::isMainThread()
{
    return QThread::currentThread() == qApp->thread();
}

We create a Worker object, a QThread object and connect them with each other:

QThread *thread = new QThread;
Worker *worker = new Worker;
worker->moveToThread(thread);

QObject::connect(thread, SIGNAL(started()), worker, SLOT(doWork()));
QObject::connect(worker, SIGNAL(done()), thread, SLOT(quit()));
QObject::connect(thread, SIGNAL(finished()), worker, SLOT(checkThread()));
QObject::connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));

thread->start();

That's what we got in the application output:

Worker::Worker(QObject*) QThread(0x1034680) true 
void Worker::doWork() QThread(0x1224970) false 
void Worker::doWork() Work is done 
void Worker::checkThread() QThread(0x1034680) true 

A Worker object is being created in the main application thread, then it does its work in a new thread. After job is done, it sends done() signal and moves itself back to the main thread. After a thread is finished we check that our Worker object is now really in the main thread again.

But really I don't understand why you may need this.

hank
  • 9,553
  • 3
  • 35
  • 50
  • Okay but how to do it? Just calling `moveToThread` with the new thread? – Maxbester Apr 17 '13 at 06:56
  • Do in like in your sample, but first start thread and then call moveToThread method. – Dmitry Sazonov Apr 17 '13 at 07:52
  • I updated the question. I try to move back the object to the main thread. But with same result... – Maxbester Apr 17 '13 at 12:12
  • @hank: Thanks for the example. I agree with it. I've already tried it but it fails. The problem comes from the line `moveToThread(qApp->thread());`. Same error message... Anyway, if you want to understand my need, have a look at [this post](http://stackoverflow.com/q/15904958/902025). – Maxbester Apr 17 '13 at 14:53
  • @Maxbester The code above works fine for me, I've got no errors. I think you can specify a connection type in every connect function: `Qt::QueuedConnection`. – hank Apr 17 '13 at 15:04
  • @hank Yes I've already done it but with no luck... I am stuck. By the way, I am probably not catching the `done()` signal because the last call of `checkThread()` is not done. – Maxbester Apr 17 '13 at 15:25