PDA

View Full Version : Executing slots in a separate QThread?



kachofool
9th December 2009, 01:14
Hey all,

I have a quick question regarding the start up of a new thread, separate to the main thread, and executing a slot in it, from a signal invoked from the main GUI thread. I understand this behaviour is not normally recommended.

I created a simple subclass of QThread and connected a signal from my main thread to a slot in the subclassed thread. The slot prints out the current thread id. Initializing my class object in the main thread also prints out the current thread id. However, both these threads have the same id... aren't they supposed to be different? I'm using QThread::currentThread() to return the ID, and I read there might be issues using this with win32, but I'm on Linux. I've provided my source at the bottom of the post.

## output ##

Main thread is 0x90fd250
Executing Slot in 0x90fd250
Executing Slot in 0x90fd250
Executing Slot in 0x90fd250


If I move the thread object to the actual thread, (using moveToThread), the results are as expected:


Main thread is 0x8ac5250
Executing Slot in 0x8ace860
Executing Slot in 0x8ace860
Executing Slot in 0x8ace860


I just wanted to know if using moveToThread is the right way to do this (what if the thread quits or is terminated?)


## main.cpp ##

#include <QtCore/QCoreApplication>
#include "test.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

MyObject thisIsATest;

return a.exec();
}



## test.h ##


#include <new>
#include <iostream>
#include <iomanip>
#include <stdlib.h>
#include <vector>
#include <time.h>
#include <math.h>
#include <fstream>
#include <sstream>
#include <stdexcept>

// Qt Includes
#include <QThread>
#include <QMutex>
#include <QString>
#include <QWaitCondition>

class MyObject;
class MyThread;

class MyThread : public QThread
{
Q_OBJECT

public:
MyThread(MyObject* ptr, QObject *parent = 0) { MyObjectPtr = ptr; }
~MyThread() {}

public slots:
void MyThreadsStartup();
void MyThreadsSlot();

protected:
void run();

private:
MyObject* MyObjectPtr;

};

class MyObject : public QObject
{
Q_OBJECT

public:
MyObject(QObject *parent = 0);
~MyObject() {}

signals:
void TriggerThread();

private:
MyThread* myThread;

};


## test.cpp ##

#include "test.h"


void MyThread::MyThreadsStartup()
{ QObject::connect(MyObjectPtr, SIGNAL(TriggerThread()), this, SLOT(MyThreadsSlot()));
//moveToThread(this)
}

void MyThread::MyThreadsSlot()
{ std::cerr << " Executing Slot in " << QThread::currentThread() << std::endl; }

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


MyObject::MyObject(QObject *parent) : QObject(parent)
{
std::cerr << " Main thread is " << QThread::currentThread() << std::endl;
myThread = new MyThread(this);
myThread->MyThreadsStartup();
myThread->start();


emit TriggerThread();
emit TriggerThread();
emit TriggerThread();
}



Regards,

-KF

Tanuki-no Torigava
9th December 2009, 06:40
Hi,

just corrected your code a bit:

Here it is results:


./threadtest
Main thread is MyObject(0x7fff6d5b6280)
Executing Slot in MyThread(0x60b9d0)
Executing Slot in MyThread(0x60b9d0)
Executing Slot in MyThread(0x60b9d0)


Corrected code below:

test.h



// Qt Includes
#include <QThread>
#include <QMutex>
#include <QString>
#include <QWaitCondition>

class MyObject;
class MyThread;

class MyThread : public QThread
{
Q_OBJECT

public:

MyThread(QObject *parent = 0) {}
~MyThread() {}

public slots:

void MyThreadsSlot();
void refMyObject(MyObject* theValue);

protected:
void run();

private:

MyObject* MyObjectPtr;

};

class MyObject : public QObject
{
Q_OBJECT

public:
MyObject(QObject *parent = 0);
~MyObject() {}

signals:

void TriggerThread();
void refMe(MyObject* theValue);

private:

MyThread* myThread;
};


test.cpp



#include "test.h"
#include <QDebug>

void MyThread::refMyObject(MyObject* theValue)
{
MyObjectPtr = theValue;
QObject::connect(MyObjectPtr, SIGNAL(TriggerThread()), this, SLOT(MyThreadsSlot()));
}

void MyThread::MyThreadsSlot()
{
qDebug() << " Executing Slot in " << this;
}

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


MyObject::MyObject(QObject *parent) : QObject(parent)
{
qDebug() << " Main thread is " << this;
myThread = new MyThread();
QObject::connect(this, SIGNAL(refMe(MyObject *)), myThread, SLOT(refMyObject(MyObject*)));
myThread->start();

emit refMe(this);

emit TriggerThread();
emit TriggerThread();
emit TriggerThread();
}


main.cpp


#include <QtCore/QCoreApplication>
#include "test.h"

int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);

MyObject thisIsATest;

return a.exec();
}

wysota
9th December 2009, 08:08
I have a quick question regarding the start up of a new thread, separate to the main thread, and executing a slot in it, from a signal invoked from the main GUI thread. I understand this behaviour is not normally recommended.
It's fine.


I just wanted to know if using moveToThread is the right way to do this (what if the thread quits or is terminated?)

Moving the thread controller to the thread it controls is ok. If the thread quits, the object will probably go back under control of the thread that spawned the child thread in the first place (although that's just my assumption). If you want to do it another way then there is a very easy way to do it. In run() create an object of a new class that will contain the slot you want executed (instead of placing the slot where you have it now - in the thread class).

Here is an example:

class SolutionBringer : public QObject {
Q_OBJECT
public:
//...
public slots:
void MyThreadSlot() { ... }
};

class Thread : public QThread {
Q_OBJECT
public:
// ...
void run() {
SolutionBringer bringer;
connect(this, SIGNAL(TriggerThread()), &bringer, SLOT(MyThreadSlot()));
emit ready();
exec();
}
signals:
void TriggerThread();
void ready();
};

// ...

Thread *thread = new Thread(...);
connect(obj, SIGNAL(TriggerThread()), thread, SIGNAL(TriggerThread()));
QEventLoop loop;
connect(thread, SIGNAL(ready()), &loop, SLOT(quit()));
thread->start();
loop.exec(); // wait until the thread signals it started its work
// ...

kachofool
11th December 2009, 20:02
Thanks to both for the replies! Sorry to bump this thread up again, I just wanted to confirm -- when any QObject receives signals, the exec() event loop of the thread it lives in dispatches those signals right?

That's why you can either have one object be both your actual object and thread object (in this case the object is your thread controller and has whatever custom functionality was required to create the object in the first place as well), *or* you can have two objects, one to solely define your thread, and one for the custom object. In both cases, the object needs to live inside the thread to have its signals dispatched by the thread's exec() loop. Is this correct?