PDA

View Full Version : QGraphicsScene and QThread



tts80
9th January 2007, 06:05
Hi all,

I am using QGraphicsScene and QGraphicsView for rendering 2D graphics of vehicle traffic simulation. I want user to be able to control the simulation (i.e. start, stop and pause) so I assume QThread is required to prevent the GUI from freezing while the system does all the computation for the simulation.

I was wondering if it is a good idea to actually share the scene data between QGraphicsView and QThread subclasses. Will there be any complication in situation where QGraphicsView is redrawing while QThread tries to update the scene? Would it be safer to somehow render my scene to a QImage then draw the image instead? Hope someone can advice on this. Thanks.


Thuan Seah Tan

wysota
9th January 2007, 06:32
I am using QGraphicsScene and QGraphicsView for rendering 2D graphics of vehicle traffic simulation. I want user to be able to control the simulation (i.e. start, stop and pause) so I assume QThread is required to prevent the GUI from freezing while the system does all the computation for the simulation.
Not necessarily. You can divide the computation into steps and use a timer with 0 timeout to trigger slots which will do the computation. This way you won't block the event queue and will be able to do everything in one thread. Alternatively you can use QCoreApplication::processEvents() to force event processing during a complex operation.


I was wondering if it is a good idea to actually share the scene data between QGraphicsView and QThread subclasses.
Definitely not. You'll run into synchronisation problems.


Will there be any complication in situation where QGraphicsView is redrawing while QThread tries to update the scene? Would it be safer to somehow render my scene to a QImage then draw the image instead? Hope someone can advice on this. Thanks.
It would be best to avoid using the thread at all :)

jwintz
9th January 2007, 22:42
Hello,

Tts80 adressed TMO a very interesting problem. I also need to implement some kind of "deamons" in my application. By deamon, I mean a piece of code running in background to maintain a datastructure according to the user interaction.

This requirement led me to implement these algorithms as threads. Of course, the thread has to deal with objects inheriting QObject that are reentrant but also to interact with GUI elements which are not reentrant. Of course I have problems when the thread interacts with widgets but I've not yet understood what really is the problem in using widgets in threads (I think the Trolls documentation is not explicit enough about that). Moreover, the nature of these problems vary, depending on the platform I'm using (MacOSX or Ubuntu ...). Another point that led me to the design of threads is that these computations might be quite heavy, I do not want to freeze the application during them.

QCoreApplication::processEvents() (http://doc.trolltech.com/4.2/qcoreapplication#processEvents) processes all pending events according to the specified flags until there are no more events to process. Does it actually postpone a computation using a priority queue ?

So Wysota, you suggest a general workaround to replace threads ? Could you give us a short example ? In which case do you suggest using threads (except for network stuff of course), in which case do you suggest to avoid using threads ?

Thanks, Julien.

wysota
9th January 2007, 23:50
Of course I have problems when the thread interacts with widgets but I've not yet understood what really is the problem in using widgets in threads
You may be accessing internal QWidget data from within two different threads trashing it effectively.


QCoreApplication::processEvents() (http://doc.trolltech.com/4.2/qcoreapplication#processEvents) processes all pending events according to the specified flags until there are no more events to process. Does it actually postpone a computation using a priority queue ?
No, it simply calls the event queue and processes it. You might say that when you call QApplication::exec() its implementation (of course this is a simplification!) looks like:
while(!end) processEvents();


So Wysota, you suggest a general workaround to replace threads ?
Only when it's appropriate :)


Could you give us a short example ?

I can. Imagine you want to generate a large amount of random numbers and spit it out in your app. In a non-GUI app you would simply do:


int main(){
for(int i=0;i<10000;i++)
printf("%d\n", rand());
return 0;
}

In a GUI app you do the same, just redirect the output to some widget. The problem is that it blocks the application until the loop exits.

So an obvious workaround is to use threads:


class MyThread : public QThread {
Q_OBJECT
public:
MyThread(QTextEdit *edit, QObject *parent=0) : QThread(parent){
connect(this, SIGNAL(generated(const QString &)), edit, SLOT(append(const QString &)));
}
void run(){
for(int i=0;i<10000;i++)
emit generated(QString::number(rand()));
}
signals:
void generated(const QString &);
};

int main(int argc, char **argv){
QApplication app(argc, argv);
QTextEdit te;
MyThread thread(&te, &app);
thread.start();
return app.exec();
}

This should work as expected, but there is really no point in using the worker thread as you can achieve the same by:


class Dummy : public QObject {
Q_OBJECT
public:
Dummy() : QObject(){ cnt = 0; }
void start(){
QTimer::singleShot(0, this, SLOT(generate()));
}
public slots:
void generate(){
emit generated(QString::number(rand()));
if(++cnt<10000)
QTimer::singleShot(0, this, SLOT(generate())); // "schedule" next timeout immediately
}
signals:
void generated(const QString &);
private:
int cnt;
};

int main(int argc, char **argv){
QApplication app(argc, argv);
QTextEdit te;
Dummy obj;
app.connect(&obj, SIGNAL(generated(const QString &)), &te, SLOT(append(const QString &)));
obj.start();
return app.exec();
}


In which case do you suggest using threads (except for network stuff of course), in which case do you suggest to avoid using threads ?
Why except network stuff? You can do network stuff with Qt without or with using threads.

In general threads should be used when the amount of work to do is heavy, can't be split into chunks (if it can, you can use the timer approach), you need many workers, it's not important that the task is executed immediately or in situations when it's simply very convenient to use threads.

DISCLAIMER: The code above was not tested, don't assume it to work :)

jwintz
10th January 2007, 08:34
In general threads should be used when the amount of work to do is heavy, can't be split into chunks (if it can, you can use the timer approach), you need many workers, it's not important that the task is executed immediately or in situations when it's simply very convenient to use threads.

I completely agree with your example. This piece of code is a blocking task, but it is a "finite" task.

Let's go back to our kinds of so-called "deamons". They are functionalities that can be run, suspended, re run again or completely stopped. Of course this handling of the task can also (and is in some sense), achieved by using signals (maybe using something like "disconnect", if it exists) but the main point is that we cannot know how long it will exist, it is an infinite task.

So here is my first question: Does not using QTimers for such purposes induces avoidable computations ?

And my second question: Does emitting signals to GUI widgets (that are not reentrant) from a thread completely avoids crashes due to the access of widgets data from a thread ?

Is so I might reconsider my threads ;-)

Thanks for your precisions!

wysota
10th January 2007, 09:32
Of course this handling of the task can also (and is in some sense), achieved by using signals (maybe using something like "disconnect", if it exists) but the main point is that we cannot know how long it will exist, it is an infinite task.
That doesn't matter. You can even use QObject::timerEvent() to avoid using an external timer, start the internal object timer and let it tick.


So here is my first question: Does not using QTimers for such purposes induces avoidable computations ?
It probably depends what you want to do and how your "daemons" are to work. For example if they are to work in an irregular way - they access a database using a blocking call, they access the disk very much, they wait until something else happens - then it is better to use threads for that. But if they just do the things in a regular way (for example update a clock widget, draw a chart, etc.), then you can do it with timers. Also note the fact, that using the timer approach with too many timers will slow down the application as all the actions will be executed when the time comes. With threads they can be deferred a little (until a context switch), making your application more responsive (nothing steals the CPU from the GUI).


And my second question: Does emitting signals to GUI widgets (that are not reentrant) from a thread completely avoids crashes due to the access of widgets data from a thread ?
Yes, signals are thread-safe in Qt4 as they'll use a thing called queued connections - consult the docs for details.