PDA

View Full Version : Receiving slots in QThread's context ?



The Storm
13th August 2010, 21:24
Hello,

Is it possible signal emited from the main(or other) thread to be received in a slot inside the QThread context? I have failed to accomplish that so far...

Here's what I'm basically doing:


class MyThread : QThread
{
Q_OBJECT:

public:
MyThread() {}
~MyThread() {}

void addNewStuff()
{
// This method is called from the main thread
emit newStuff();
}

protected:
virtual void run()
{
connect( this, SIGNAL(newStuff()), this, SLOT(onNewStuff()) );
exec();
}

private slots:
void onNewStuff()
{
// My slot also is called from the main thread... :(
QThread::currentThreadId();
}

signals:
void newStuff();
};


MyThread is created and started from the main thread. At some point the main thread will call addNewStuff() method which I'm expecting to call onNewStuff() in the MyThread context, not in the main thread's one. So far my slot is always called from the main thread context... I also tried changing the flags of the connect() method but with no luck.

Any help will be appreciated. :)

squidge
13th August 2010, 21:53
have a look at moveToThread

The Storm
13th August 2010, 21:59
I had. I guess that you are not suggesting to call moveToThread(this) in the run method, because I had read that this is wrong.
Can you provide more details please?

Lykurg
13th August 2010, 22:38
connect( this, SIGNAL(newStuff()), this, SLOT(onNewStuff()) );
This makes no sense. You could call your local function direct...
Since I don't know what you really want, here is a markup what you might search:
main()
{
MyThread a;
MyThread b;
GuiClass mainWindow;

connect(&a, SIGNAL(someSignal()), &b, SLOT(someSlot()));
connect(&mainWindow, SIGNAL(someSignal()), &a, SLOT(someSlot()));
}


EDIT: Don't realized your last paragraph, what's about QMetaMethod::invokeMethod with Qt::AutoConnection/Qt::QueuedConnection?

The Storm
14th August 2010, 00:16
Same result...

tbscope
14th August 2010, 09:51
Try this:
Note that I didn't test this if it compiles.

myobject.h


#include <QObject>

class MyObject: public QObject
{
Q_OBJECT

public:
MyObject(QObject *parent = 0);

public slots:
void slotInMyObject();
};


myobject.cpp


#include "myobject.h"

MyObject::MyObject(QObject *parent)
: QObject(parent)
{
}

void MyObject::slotInMyObject()
{
//Do something
}


mywidget.h

#include <QWidget>

class MyWidget : public QWidget
{
Q_OBJECT

public:
MyWidget(QWidget *parent = 0);

signals:
void signalFromMyWidget();
};


mywidget.cpp


MyWidget::MyWidget(QWidget *parent)
: QWidget(parent)
{
}

...


Emit a signal somewhere, but try to emit only signals when all objects are created in the main thread and all objects are moved to the correct thread. Otherwise you will pull your hair out.

I have no idea if QThread starts the eventloop automatically. If not, use the following thread class.
mythread.h


#include <QThread>

class MyThread : public QThread
{
public:
void run();
};


mythread.cpp


void MyThread::run()
{
exec();
}


Then put it all together:

main.cpp


#include "myobject.h"
#include "mywidget.h"
#include "mythread.h"

int main(...)
{
QApplication a(...);

MyWidget *w = new MyWidget;
MyObject *o = new MyObject;
MyThread *t = new MyThread;

connect(w, SIGNAL(signalFromMyWidget()), o, SLOT(slotInMyObject()));

o->moveToThread(t);

t->start();

w->show();

return a.exec();
}


I might have forgotten something, but that's the basics.

The Storm
14th August 2010, 12:06
Thanks, this one worked. I just wonder why it can't be done with my QThread subclass... Anyway QThread automatically starts an event loop so instead of inheriting QThread I will just use QObject with regular QThread instance. :)

squidge
14th August 2010, 12:24
It can be done with a QThread subclass, but that way is typically frowned upon. If you use as above it is upto you if you wish to use threads or not.

tbscope
14th August 2010, 12:45
I just wonder why it can't be done with my QThread subclass.

The conecpt of QThread is not easy to understand by a lot of people, especially because the official documentation of QThread is not sufficient or even correct.
During the lifetime of Qt4 QThread changed, but the documentation remained the same.

Why do signals and slots in a QThread subclass not work as expected?
The only code that runs in a thread other than the main thread is the code that is written in the run() function, or that is being called from the run() function.

However, you define signal and slot functions in the QThread subclass. If you create a QThread object in your program, this QThread object lives in the main thread. Therefor the signals and slots are also define in the main thread.

Like I said above, when you call a function of QThread or a subclass from within the run() function, it will also be performed in the new thread. No problem for signals.
Slots are much more complicated.

If for example you connect a slot in your QThread subclass in the constructor of your QThread subclass, this slot will be called in the main thread!

Some people use moveToThread from within their QThread subclass. Although this SEEMS to work, it is wrong. You want to have the QThread object live in your main thread.
Therefor it is suggested to create a QObject subclass, implement it like any other object. Then create a new QThread object and move the QObject object to the new QThread object. In the background, the whole QObject object is moved to a new thread, instantly executing the slots inside the new thread.

I guess you can compare it like this:

class MyThread: public QThread
{
...
//slots
//signals
...
};

to


class MyObjectThread : public
{
public:
void run();
};

void MyObjectThread::run()
{
MyObject *obj = new MyObject;

connect(..., SIGNAL, obj, SLOT);
}


Since the object is created in the run() function, it completely lives in the new thread.

The Storm
14th August 2010, 12:46
Yes you have a point. Thanks for the help. :)

EDIT: I just missed your last post tbscope. The things you explained give me much more light on this Qt specific "things". I hope that they will soon fix up the documentation with some nice examples in order to not get more confused users like me. :)

tbscope
14th August 2010, 13:01
Just a disclaimer: This is how I understand it. But I might have posted mistakes in my explanation too.