PDA

View Full Version : Worker thread doesn't seem to start event loop?



Data42
30th August 2013, 23:48
Hi everyone,
I'm using QTimers in a multithread Qt5 application. Here is my structure:
- MainWindow.cpp creates a thread A and its worker object:

t = new QThread();
worker = new SudokuComputeWorker();
worker->moveToThread(t);
connect(t, SIGNAL(started()), worker, SLOT(doWork()));
connect(worker, SIGNAL(scoresFetched(const QList<double>*)), worker, SLOT(workDone()));
t->start();

- Thread A creates N threads B1, B2,... BN, each with its own worker object:

foreach (SearchComponent* s, algos) {
QThread* t = new QThread();
SudokuWorker* w;
w = new SudokuWorker(i, s, _myBLOCKS_SIZE, _myON_DISTRIBUTION, _myHOW_MANY_PROBLEMS);
w->moveToThread(t);
connect(t, SIGNAL(started()), w, SLOT(doWork()));
connect(w, SIGNAL(scoreFetched(int)), w, SLOT(workDone()));
t->start();
}

- Whats happens in SudokuWorker::doWork()?

void SudokuWorker::doWork()
{
QTimer* t = new QTimer(NULL);
my_AlgoToTest->attachTimer(t);

for (; _myNbTimesToRun > 0 && !_myInterruptNow; _myNbTimesToRun--) {
qDebug() << *my_AlgoToTest << _myNbTimesToRun;
SudokuState s(my_BlockSize);
my_AlgoToTest->resetAlgorithm();
my_AlgoToTest->runAlgorithm(&s);
scores.append(my_AlgoToTest->getBestReward());
testsCompleted++;
}

delete t;
emit scoreFetched(my_AlgoIndex);
}
[Notice: Normal if the sense of the code doesn't seem obvious, I just let the things in relation with the threads and the worker. Threads and objects deletion is properly set.]

Note that in attachTimer(), the timer is set as "single shot: true". Moreover, in runAlgorithm(), there is the "timer->start(1000)" statement.

Now the problem:
The timers aren't started, as if the threads in which the workers are had no event loops. Indeed, when I want to show the remaining time of the timers juste after they have started, I have random numbers (all but 1000) that shows up. This is the mark of an uninitialized value, and it occurs because somehow the timers don't find their event loop.
Have you any idea of what I'm doing wrong? I thought I applied as I had to the method presented in "You're doing it wrong"...

Thank you!!

Santosh Reddy
31st August 2013, 07:36
Thread A creates N threads B1, B2,... BN, each with its own worker object:
Whre is code in the actual software? I mean which method of Thread A?




void SudokuWorker::doWork()
{
QTimer* t = new QTimer(NULL); // Timer is createed here
my_AlgoToTest->attachTimer(t);

// Note: Timers/events will not be triggered while inside this for loop, uness explicit event processing is done.
for (; _myNbTimesToRun > 0 && !_myInterruptNow; _myNbTimesToRun--) {
qDebug() << *my_AlgoToTest << _myNbTimesToRun;
SudokuState s(my_BlockSize);
my_AlgoToTest->resetAlgorithm();
my_AlgoToTest->runAlgorithm(&s);
scores.append(my_AlgoToTest->getBestReward());
testsCompleted++;
}

delete t; // Timer is deleted here. How can you expect the deleted timer to work?

emit scoreFetched(my_AlgoIndex);
}


Worker thread doesn't seem to start event loop?
QThread by defaut starts it's event loop when start() is called, provided run() is not reimplemented. The effect of event loop can only be seen once the code control returns to the event loop. Just looping in a for loop / while loop will not trigger any events/inter thread signals/etc. All events will be handled only when the control returns to the event loop.

Data42
31st August 2013, 18:45
Hi and thanks for helping me !!
The thing is that the "runAlgorothm" is the really long part. This loop is not the thread creation loop but the algorithm test loop. So the timer is deleted after all tests have been done (for each test, I restart the timer in runAlgorithm).

The second piece of code I showed you is the doWork method of thread A, that is in charge to create the threads Bi.

I don't exactly understand when you say that the event loop is stucked as long as I'm looping in my algorithms tests. The run() method of threads A and Bi are left untouched, not reimplemented. I just connect the started() signal of the thread to the doWork() method of its worker object... So technically, when calling start(), the thread is created, the original run method is run, that is only exec(), then "started()" signal is fired and doWork is called... No ?
There is no code in run so I don't understand how the event loop could be stucked? I think I haven't understood something... And why are my timers not started properly, as if the event loop wasn't already started?

Thank you again!!

Santosh Reddy
31st August 2013, 20:04
So technically, when calling start(), the thread is created, the original run method is run, that is only exec(), then "started()" signal is fired and doWork is called... No ?
You are correct.

The point you are missing is that the timer events/signals are called/emitted from event loop, and that will occur only when control returns to the event loop. Here the doWork() (or whatever slot) is buzy doing something and thus control does not return to the event loop. Note all the slots of an objects in a thread and the event loop are executed in the same context/control/stack, which means when a slot of an object in a thread is executing another slot/event/signal of an object of same thread has to wait for the first object's slot to finish and wait for the control to return to event loop.

Data42
31st August 2013, 22:44
oh Ok, now I undesrstand : it is stucked because it waits for the slot to terminate (which will never terminate as it waits for another signal that will never be processed).
Do you have any idea of how to achieve this using the correct use of the worker threads?
Thank you for your enlightenings so far!! :)

Santosh Reddy
1st September 2013, 11:00
I don't see a reason to use QTimers, just use multiple threads with out any timers.

Data42
1st September 2013, 16:45
The thing is that I need them because I test my algorithms performances for some research and they all have a computational budget of X seconds. So I need QTimers for each to use that precise amount of time and not more...

Santosh Reddy
2nd September 2013, 07:44
The thing is that I need them because I test my algorithms performances for some research and they all have a computational budget of X seconds. So I need QTimers for each to use that precise amount of time and not more...
Looks like you want some time based scheduling which makes sure that algorithm doe not run for more than X seconds. or may you just want to measure the time consumed by each algorithm. In either cases QTimer will not help, you have use QTime


QTime t;
t.start();
some_lengthy_task();
qDebug("Time elapsed: %d ms", t.elapsed());

Data42
2nd September 2013, 18:43
That's perfect ! I didn't know about QTime, this should do the trick !
Thanks again for everything :)

anda_skoa
3rd September 2013, 09:16
Or even QElapsedTimer if you don't need to convert into hours/minutes/seconds and just want the most efficient class http://qt-project.org/doc/qt-5.0/qtcore/qelapsedtimer.html

Cheers,
_

Data42
3rd September 2013, 17:33
Indeed, it's even better for my use! Thank you :)