PDA

View Full Version : thread problem



talk2amulya
18th February 2009, 07:11
hi,

i m showing a splash screen before my application starts. The splash screen has a loading icon(a gif image). After showing the splash screen, there is some heavy processing going on because of which the loading icon doesnt animate(it stays in one single frame until the application starts). Next thing i tried was to place qApp->processEvents() at various places inside the "heavy processing code". This makes the loading icon move a bit intermittently but still its not smooth. So next thing i tried was to start a thread at the beginning of the application and have a timer run there, on each timeout of which, qApp->processEvents() will be called. But with this code, loading icon doesnt move at all. Here is the code...


#include "mythread.h"
#include <QTimer>
#include <QApplication>
MyThread::MyThread(QObject *parent)
: QThread(parent)
{

}

MyThread::~MyThread()
{

}

void MyThread::run()
{
QTimer *timer = new QTimer();
connect(timer, SIGNAL(timeout()), this, SLOT(callProcessEvents()));
timer->start(100);
exec();
}

void MyThread::callProcessEvents()
{
qApp->processEvents();
}



#include <QLabel>
#include <QMovie>
#include <QSplashScreen>
#include <QEventLoop>
#include <QTimer>
#include <QBitmap>
#include "splashthread.h"
#include "mythread.h"

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


MyThread *th = new MyThread(NULL);
th->start();
th->moveToThread(th);

QSplashScreen screen(QPixmap("C:\\Documents and Settings\\am002bh\\Desktop\\error-checkin.PNG"), Qt::WindowStaysOnTopHint);

QLabel label(&screen);
QMovie *movie = new QMovie("C:\\Documents and Settings\\am002bh\\Desktop\\bigrotation2.gif");

movie->jumpToFrame(movie->frameCount());
QPixmap WinMask = movie->currentPixmap();
label.setMask(WinMask.mask());

label.setMovie(movie);
movie->start();

screen.show();
//sm heavy processing code
th->quit();
screen.close();


what am i missing..if i call qApp->processEvents from inside the "heavy processing code", the loading icon animates..if i call that from another thread, it doesnt move at all..i cant start a timer from inside the main function either(which is why i use another thread). i need this loading icon to animate at all times untail the appliction loads(heavy processing code execution is done). Any threading gurus, please let me know how to correctly do this.

Thanks in Advance!
Amulya

^NyAw^
18th February 2009, 09:06
Hi,

I think that you have to use the thread to perform the heavy computation and let the main thread process events and update the GUI.
So, let the main thread perform the animation and the other thread to perform the heavy computation. If the thread needs to send some message to the main thread use the SIGNAL SLOT mechanism.
The thread that you have to code have not to have an event loop, it have to be something like this:



void myClassThread::run()
{
while(!bFinish)
{
//Do some work
}
//It will exit "while" when "bFinish" is true, so then the "run" method will exit and so the thread will stop
}

Cruz
18th February 2009, 09:22
I would also add a small sleep to the worker thread's event loop, so that it doesn't gobble all the cpu power and gives the main thread a chance to perform normally.



void myClassThread::run()
{
while(!bFinish)
{
//Do some work
msleep(10);
}
//It will exit "while" when "bFinish" is true, so then the "run" method will exit and so the thread will stop
}

^NyAw^
18th February 2009, 09:30
Hi,



I would also add a small sleep to the worker thread's event loop, so that it doesn't gobble all the cpu power and gives the main thread a chance to perform normally.
You don't need this.
I have an application that contain 4 classes. Every class have 2 threads(heavy computation threads). The main thread responds perfectly to GUI events like mouse clicks, ...

Note that the main thread is a thread, so it will fight to obtain CPU time as the others threads do the same.
Think that maybe the main thread only needs a few "ticks" to perform its job.

And note that this approach is not using an "eventLoop" as you said.

talk2amulya
18th February 2009, 09:49
hi guys,

thanks for ur input, but i cant move the heavy processing code into a different thread cuz it involves many GUI operations :( is there ANY other way to do it like i did..what i dont understand is why qApp->processEvents() doesnt work out of a different thread..whereas it was working in the main thread.

spirit
18th February 2009, 09:53
create propper signal/slot approach for separating gui and non-gui operation. try to revise your havy-compution algorithm.

^NyAw^
18th February 2009, 09:56
Hi,

If the heavy computation performs GUI, use SIGNAL SLOT mechanism to let the main thread do the GUI operations. It's not difficult.

But if you really want to do it as you tell, why use a thread that starts a timer? Only start a timer on the main thread and try if the calls to "processEvents" work.

talk2amulya
18th February 2009, 10:43
looks like a revising in the heavy-computation algorithm is in order....a connect in the main also doesnt work..its really strange....thanks guys for ur time!

^NyAw^
18th February 2009, 10:55
Hi,



a connect in the main also doesnt work


Is "yourClassThread" defining the "Q_OBJECT" macro?

You can take a look at console output to see why it don't connect. Note that the connections have to be "Qt::QueuedConnection" or let it autodetect.

talk2amulya
18th February 2009, 11:07
i meant i cant use connect(...) in main() because where would i put Q_OBJECT?? about Qt::QueuedConnection , yes i used that too..still didnt work..i m sure if i get to call processEvents() at a certain interval until the processing is over, i can animate the icon..but for sm reason, none of my attempts to call processEvents(), either from main() or other thread is working....

spirit
18th February 2009, 11:17
create an object in main thread (in main.cpp) which will call qApp->processEvents by QTimer::timeOut.



....
class MyProcessEventDispatcher: public QObject
{
Q_OBJECT

public:
MyProcessEventDispatcher(QObject *parent = 0)
: QObject (parent)
{
m_timer.setInterval(100);
connect(&m_timer, SIGNAL(timeout()), SLOT(updateEvents()));
m_timer.start();
}

private slots:
void updateEvents()
{
m_timer.start();
qApp->processEvents();
}
private:
QTimer m_timer;
};
#include "main.moc"
int main(int argc, char **argv)
{
QApplication app(argc, argv);
MyProcessEventDispatcher mpee;
...
return app.exec();
}

^NyAw^
18th February 2009, 11:21
Hi,



#include <QThread>
class myThread : public QThread
{
Q_OBJECT
public:
//Redefine this method with your computation
void run()
{
while(!bStop)
{
//Do some work
emit (emitShowText(QString("Hello Thread"));
...
}

}

signals:
void emitShowText(QString); //Define all the signals you want to emit
void emitShowProcessProgress(int);
}




myAppWindow::myAppWindow(QWidget *parent, Qt::WFlags flags) : QMainWindow(parent, flags)
{
ui.setupUi(this); //Setup UI if used a GUI editor like QDesigner

//Create the thread and connect it's signals to "this" slots
m_pThread = new myThread(this);
bool bC = connect(m_pThread,SIGNAL(emitShowText(QString)),th is,SLOT(showText(QString)),Qt::QueuedConnection); //Insert a debug point and take a look at console out. If connection fail it will reach error message on it

m_pThread->start(); //Enter the Thread "run" method
}

talk2amulya
18th February 2009, 11:34
for some reason


connect(&m_timer, SIGNAL(timeout()), SLOT(updateEvents()));

isnt getting connected..

spirit
18th February 2009, 11:36
I've updated code and also tested it. a slot is called normal.

talk2amulya
18th February 2009, 11:39
yeh, i made those changes too but still updateEvents() is only getting called once, until whole of the processing is done..so no help from this either..thanks though, spirit...

talk2amulya
18th February 2009, 11:47
actually there is only one function call(which makes further calls) that is doing all the heavy processing..and that function call is in main()..perhaps the control isnt going back to the other objects or timers cuz of it..could that be true? just cuz one particular function has to execute, the control will go nowhere else?

spirit
18th February 2009, 11:49
yes this is possible. so, try to call processEvents in that "havy" function.

^NyAw^
18th February 2009, 11:56
Hi,

Calling "processEvents" is not a good idea. I think if you call it many times it ignore some of them.

Have you ported your heavy computation inside the thread? You will not need to call "processEvents" then. You emit SIGNALs and let the main thread do its work.

spirit
18th February 2009, 11:59
maybe this can help you Keeping the GUI Responsive (http://doc.trolltech.com/qq/qq27-responsive-guis.html)

talk2amulya
18th February 2009, 11:59
that is EXACTLY what i did sm days back..and the icon animates cuz of it as desired..although intermittently ..but i had to place like 30 calls to processEvents() here and there inside it..and if i want it to be done smoothly i might need more..so thats why i was wondering there should be a better way to do it in QT..so i went with using timers and on timeout, calling processEvents(), but evidently it also has no effect..which i find really surprising...anyone has anymore info about processEvents()??or smth else that could resolve this issue?

talk2amulya
18th February 2009, 12:00
i have already read that link..and i have tried sm of the ways that fits my needs..but none of them worked..

talk2amulya
18th February 2009, 12:05
hi oscar,

the heavy processing code contains some GUI calls, so i cant put that in another thread.. even if it was to be done..it'd be a lot of work..i m looking for a solution that bypasses me having to change anything in the way the things are done currently