PDA

View Full Version : QThread - general understanding



soul_rebel
8th August 2007, 16:16
some things have changed with threading between qt3 and qt4 so i dont really understand how to do things now.

my situation/plan:
i have "class A" that has a member function "b()" that does a lot of processing. i dont want it to lock up the interface so i create an object of "class C : public QThread" which i pass a pointer to object "o" of type A and then have it call o.b().

now the problem is where in C do i call o.b()? i remember that in qt3 i would just call that from run() but all this eventloop thingy confuses me....
does starting a seperate eventloop mean, all member functions of the thread are executed in the thread's eventloop?
so i could put "exec()" into "run()" and put that into the constructor and after that all members would be executed in that thread?
or do i still need to put all calls inside the run()-function that i want to be executed "inside the thread"? and if so, would i run exec() before those functions inside run() or after those functions.
my calls do emit signals that slots in main's eventloop catch, but that supposed to be taken care of with QueuedConnections if i understood correctly....

thanks for any help!!

marcel
8th August 2007, 16:27
now the problem is where in C do i call o.b()? i remember that in qt3 i would just call that from run() but all this eventloop thingy confuses me....
does starting a seperate eventloop mean, all member functions of the thread are executed in the thread's eventloop?

You can do it in run.
Starting the event loop with exec() is needed only if there are objects in the thread that require an event loop, such as QTimers.
Also, an event loop is needed if you want to connect signals from other threads to slots in your thread, since the signals will actually be posted as events.

So, it is safe to call the function in run.




my calls do emit signals that slots in main's eventloop catch, but that supposed to be taken care of with QueuedConnections if i understood correctly....

Yes, if you emit them from the other thread, they will default to queued connections, although the "o" instance lives in the GUI thread.

Regards

soul_rebel
8th August 2007, 17:02
hm ok i understand that so far, so i could if i want to make it short put o.b() inside run() and call run from the constructor, i could also make a connection inside the constructor that connects finished() with deleteLater() so that the thread cleans up after itself, or would that cause problems? ( the finished() signal is emited outside the thread isnt it?)


at a different point in my program i would like slots inside a thread to be able to receive signals from outside. to be more specific, i would like to pipe the output from a qprocess to a thread for processing. is it possible to do that, or are slots in threads generally not executed within the thread? or would a situation like that require an extra eventloop?

thanks alot for your help!!

marcel
8th August 2007, 17:10
hm ok i understand that so far, so i could if i want to make it short put o.b() inside run() and call run from the constructor,

You need to call QThread::start(), not run() directly.



i could also make a connection inside the constructor that connects finished() with deleteLater() so that the thread cleans up after itself, or would that cause problems? ( the finished() signal is emited outside the thread isnt it?)

You could do this when you instantiate the thread, but the finished signal occurs only after the thread finishes, so it is better to connect it to a slot outside the thread.



at a different point in my program i would like slots inside a thread to be able to receive signals from outside. to be more specific, i would like to pipe the output from a qprocess to a thread for processing. is it possible to do that, or are slots in threads generally not executed within the thread? or would a situation like that require an extra eventloop?

You will have to start the event loop for the thread.
When you say "extra event loop" you make it sound like a bad thing. It is not. You can start an event loop for every thread.

The slots are executed in the thread context, but only if you move the thread to it's own context.
A QObject's slots are executed in the parent thread. You first create the QThread in the GUI thread, so you must call moveToThread in order to make sure the slots are executed in the thread.

Regards

soul_rebel
8th August 2007, 18:40
You need to call QThread::start(), not run() directly.
right.


You could do this when you instantiate the thread, but the finished signal occurs only after the thread finishes, so it is better to connect it to a slot outside the thread.
hm but i dont want the calling object to have to bother that much, it would be great if could just "new" the thread object, and have do what it does and then dissapear and delete itself...


You will have to start the event loop for the thread.
When you say "extra event loop" you make it sound like a bad thing. It is not. You can start an event loop for every thread.
no didnt mean to say its a bad thing ;)


The slots are executed in the thread context, but only if you move the thread to it's own context.
A QObject's slots are executed in the parent thread. You first create the QThread in the GUI thread, so you must call moveToThread in order to make sure the slots are executed in the thread.
wow, moveToThread looks powerful, i could basically create thread that does nothing but start an eventloop, than create a qprocess in the guithread and push it to that thread and make directconnections from the qprcocess' readyRead-signal to slots in the gui-thread but because the signals originate from the child thread and the connection is direct these slots are executed inside the thread!?
that would be awesome!


thanks alot for your help!!

marcel
8th August 2007, 18:51
wow, moveToThread looks powerful, i could basically create thread that does nothing but start an eventloop, than create a qprocess in the guithread and push it to that thread and make directconnections from the qprcocess' readyRead-signal to slots in the gui-thread but because the signals originate from the child thread and the connection is direct these slots are executed inside the thread!?
that would be awesome!
Well, that should double checked, but the last time I checked QMetaObject::activate, that is what it was doing.

But this is bad design. Why don't you create the QProcess in the thread? Or lose the thread at all, since a QProcess executes asynchronously.

You shouldn't be playing with that functionality. You either do it like it is supposed to be done, or you do it another way.
Generally, you use a thread if you have some heavy operation to perform and you want GUI interactivity, or if you want something to be performed in the background.

QProcess will do just fine by itself.

Regards

soul_rebel
8th August 2007, 19:13
hm i understand your concerns but it looks cleaner to me than doing it in other ways. the problem is that the qprocess runs something that produces a lot of output over a long time. this output has to be processed line-by-line and for each line operations are done that may need a lot of time by themself. now if the guithread receives the readready-signal it would starts processing the new output and block until it is done (maybe to immediately start with the next lines of output).
also i have really many different ones of thes qprocess and dont want to spam my file with loads of extra qthread-objects.
AND if i do it this way i can "#ifdef USETHREADS" the part where qprocess is pushed to the thread and thus have a threads- and a nothreads-version should i want that (e.g. for a CLI).

soul_rebel
21st August 2007, 17:47
another question i came upon thinking about threads:
if connection type is set to auto, is the state of the connection defined at "connection-time" or on a per-signal basis?

to explain:
lets say i have static public function that emit signals. i create a connection (from inside the gui-thread) to a gui-slot. when the connection is established both objects live in the same thread so the connection would be direct.
but if the static public function is called from inside a qthread the connection must not be direct! what will happen?
thx!

marcel
21st August 2007, 17:57
lets say i have static public function that emit signals. i create a connection (from inside the gui-thread) to a gui-slot. when the connection is established both objects live in the same thread so the connection would be direct.
but if the static public function is called from inside a qthread the connection must not be direct! what will happen?
You need an instance to emit signals. It cannot be done from static functions.
When you connect a slot to that signal, how would you do it without an instance?



if connection type is set to auto, is the state of the connection defined at "connection-time" or on a per-signal basis?

QConnection holds the type of the connection. Therefore you set the connection type when you make the connection.


struct QConnection {
QObject *sender;
int signal;
QObject *receiver;
int method;
uint refCount:29;
uint type:3; // 0 == auto, 1 == direct, 2 == queued, 4 == blocking
int *types;
};

Regards

soul_rebel
22nd August 2007, 00:11
You need an instance to emit signals. It cannot be done from static functions.
When you connect a slot to that signal, how would you do it without an instance?
it is not a static function exactly. i use a singleton class for global stuff. i have a static pointer to an object of that class, so technically the function isnt static.


QConnection holds the type of the connection. Therefore you set the connection type when you make the connection.
well but i can set it to auto. and the question is, if it is set to auto and the sender emits the signal will it check right then whether the receiver lives in the same thread or will it do that once when the connection is made?

thanks for your help

marcel
22nd August 2007, 00:15
well but i can set it to auto. and the question is, if it is set to auto and the sender emits the signal will it check right then whether the receiver lives in the same thread or will it do that once when the connection is made?

No, this is checked at emit time.
This is valid also for DirectConnection, at least. Qt will double check in QMetaObject::activate where the two objects live and decides what connection type it should use.

You could see this by debugging an emit statement.

Regards