PDA

View Full Version : Questions about slot execution.



skimmer
13th September 2012, 10:39
Assumme I have a qapplication with a qmainwindow.
In the qmainwindow is a timer emitting the signal timeout(). This signal is connected to a slot computeAlot() which does a lot of computing.

Something like this:

main.cpp


#include <QApplication>
#include "mainWindow.h"
int main(int argc, char* argv[])
{
QApplication application(argc, argv);
MainWindow mainWindow(0);
mainWindow.show();
return application.exec();
}

mainWindow.h:


#include <QMainWindow>
#include <QTest>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget * parent = 0);
private slots:
void computeAlot();
}

mainWindow.cpp


#include "mainWindow.h"
MainWindow::MainWindow(QWidget *parent)
{
const int updateRate = 10; //ms
const Qt::ConnectionType connectionType = Qt::QueuedConnection;
QTimer timer;
connect(timer, SIGNAL(timeout()), this, SLOT(computeAlot()), connectionType);
timer.start(updateRate);
}
MainWindow::ComputeAlot()
{
const int computationTime = 500; //ms
// Should do some computions here
QTest::qSleep(computationTime);
}


If the computationTime is higher than the updateRate how often will ComputeAlot() be executed if the timer stops after 100ms? Is it executed 10 times or one time or some threshold times?
Is this behavior dependent of the connectionType?
Would there be a different behavior if the ComputeAlot() would be executed in a different thread?

And if I want the computeAlot() slot be executed as often as possible while the GUI stays responsive, how do i do that? I discovered if I set the updateRate to 0 the GUI is not nicely responsive.

Thanx

wysota
13th September 2012, 11:52
Timers are checked when the event loop processes all its events. Thus if you have a timer set to 100ms but there is something that prevents the event loop from processing its events (like your heavy computation) then it won't check the timer, thus the best interval you can get in a single thread is the time of the heavy computation + some additional delay for processing other events. Thus with 100ms timer and 500ms computation, you will get an average of 120 triggers per minute.

If you use multiple threads then signals will be emitted using the same rule as mentioned above, but slot executions in a different thread will be queued and you'll get lags. Thus your slot will still be executed about 120 per minute but you can run out of memory (as signals will be getting stacked in the event loop) or after you stop the timer in the first thread, the other thread will still take a lot of time to catch up.

If you want "as often as can be" semantics, use 0 timers. Your gui will still be lagging (because you'll be blocking the event loop for 500ms all the time) though. Alternatively read this article: Keeping the GUI Responsive and apply the step-by-step approach.

skimmer
13th September 2012, 12:41
Thank you.



Thus if you have a timer set to 100ms but there is something that prevents the event loop from processing its events (like your heavy computation) then it won't check the timer

So it will also block other events, as soon as the timer executes the slot. And the timer will not emit the signal as soon as it would be time for it. The signal will be emitted only every 500ms (also not every 600ms)


Thus with 100ms timer and 500ms computation, you will get an average of 120 triggers per minute.
Okay clear, 120/min => 500ms period.


If you want "as often as can be" semantics, use 0 timers. Your gui will still be lagging (because you'll be blocking the event loop for 500ms all the time) though. Alternatively read this article: Keeping the GUI Responsive and apply the step-by-step approach.
I will read that article first.

wysota
13th September 2012, 13:17
The signal will be emitted only every 500ms (also not every 600ms)
It will be emitted not more often than every 500ms. It could be 500, 505, 600 or even 1E+10ms.

skimmer
13th September 2012, 13:34
Good.
With the proposed workerThread solution its simply solved in the easy case above. Here is my test code:


class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget * parent = 0);
private slots:
void computeAlot();
private:
int m_computationTime;
};

MainWindow::MainWindow(QWidget *parent) :
m_computationTime(500)
{
const int totalRunTime = 5000;//ms
const int updateRate = 100; //ms
const Qt::ConnectionType connectionType = Qt::QueuedConnection; //Qt::DirectConnection
QTimer * timer = new QTimer;
WorkerThread * workerThread = new WorkerThread;
workerThread->m_computationTime = m_computationTime;

connect(timer, SIGNAL(timeout()), workerThread, SLOT(start()), connectionType);
//connect(timer, SIGNAL(timeout()), this, SLOT(computeAlot()), connectionType);

timer->start(updateRate);
QTimer::singleShot(totalRunTime, timer, SLOT(stop()));
}
void MainWindow::computeAlot()
{
qDebug("Computig a lot ...");
QTest::qSleep(m_computationTime);
qDebug(" ...Computed a lot");
}



class WorkerThread : public QThread
{
public:
void run();
int m_computationTime; //ms
};
void WorkerThread::run()
{
qDebug("Computig a lot in a thread ...");
QTest::qSleep(m_computationTime);
qDebug(" ...Computed a lot");
}


Where the "computation" is done 9 times and the GUI is responsive all the time.