PDA

View Full Version : QThread in Qt4.4



ColonelMoW
30th May 2008, 21:42
Hi!

Due to the well known bug with TableView in combination with sorting I had to switch from
Qt 4.3 to Qt 4.4. Everything went pretty well until it tried my threading-classes. Here I have a strange issue which I haven't had with Qt 4.3. I wrote a small example:

mythread.h:


#ifndef MYTHREAD_H
#define MYTHREAD_H

#include <QThread>
#include <QTimer>
#include <QDebug>

class MyThread : public QThread
{
Q_OBJECT
public:
MyThread(QObject *parent = 0) : QThread(parent){}
~MyThread(){ delete timer;}

void run(void)
{
qDebug() << "head of run";
timer = new QTimer;
timer->setSingleShot(true);
timer->setInterval(1000);

connect( timer, SIGNAL(timeout()), this, SLOT(restartTimer()));

timer->start();

qDebug() << "about to start event loop";
exec();

}

private slots:
void restartTimer(void)
{
timer->start();
qDebug() << "Timer restarted";
}

private:
QTimer *timer;
};

#endif //MYTHREAD_H



main.cpp:


#include <QtGui>
#include "mythread.h"


int main(int argc, char* argv[])
{
QApplication app(argc, argv);

MyThread thread;
thread.start();

return app.exec();
}


When I compile it with Qt 4.4.0 I get the following output:
head of run
about to start event loop
QObject::startTimer: timers cannot be started from another thread
Timer restarted

And then nothing. Which is logical because it can't access the timer. But why?
Maybe someone could try this code on his machine. It would be really great!
Or maybe someone could tell me why this doesn't work...:confused:

Have a nice evening

Col

jpn
30th May 2008, 21:48
The restartTimer() slot gets executed in "wrong" thread context. You may force the connection as direct to get the slot executed in "correct" thread context:

connect( timer, SIGNAL(timeout()), this, SLOT(restartTimer()), Qt::DirectConnection);

MaximA
30th May 2008, 22:03
I'm new to threads and I try to wrap my head around it for quite some time (with only little success ;) ):

Am I right with saying: the wrong context results, because the "thread.start()" is called before "return app.exec()" ?

jpn
30th May 2008, 22:23
I'm new to threads and I try to wrap my head around it for quite some time (with only little success ;) ):
The multi-threading presentation by Brad Hughes, available at http://labs.trolltech.com/page/Projects/DevDays/DevDays2007 and the introduction to QThreads available at http://ics.com/icsnetwork/ are worth reading and watching.


Am I right with saying: the wrong context results, because the "thread.start()" is called before "return app.exec()" ?
Well not quite. :) QCoreApplication::exec() starts and event loop (in the main thread). QThread::start() just begins the execution of another thread. A QThread may optionally enter to its own event loop by calling QThread::exec().

MaximA
30th May 2008, 23:15
Thank you very much for the links, I'm looking forward to watch/read into it :)


... A QThread may optionally enter to its own event loop by calling QThread::exec().

Which the OP does in his thread (line 27).
;) Is the connect called to early, doesn't it therefore not belong to the eventloop of the thread....(I thought, with my -in the meantime- totally toasted brain, that the threat is "autonomous" because everything is inside- even its own event-loop.... aarrrggg :lol:
Please don't be bothered by my stupid understanding, and it's okay if you don't want to answer (you have probably answered this kind of question a million times)

In any case thanks for listening!
And have a nice & stupid-free weekend :lol:

EDIT: I've just read http://www.qtcentre.org/forum/f-newbie-4/t-qt-threading-13939.html and get a feeling of an understanding (thanks for the effort!)

lyuts
2nd June 2008, 07:59
Why do you connect timeout() to restartTimer()? What if you write use setSingleShot(false)? This will restart timer automatically after it fires.

ColonelMoW
2nd June 2008, 18:06
@lyuts
You're right. That was just for demonstration purposes.

I did a lot of research and I found my error:
All Slots, attributes, routines, ... of the QThread-class belong
to the Thread that instantiated the QThread-object.

A wrote a QObject-class that is now instantiated on the stack
of the run()-routine. Now I can access all slots of my QObject via QueuedConnections and they run in the right thread.

Thank you everyone for your Help.

btw. Of course in this particular problem I can use a DirectConnection. That way
the slot is executed in the calling threat. Thank you jpn - that actually brought me on the right track.

Col