PDA

View Full Version : The right approach to "ask" data to the running thread..



sylvaticus
1st January 2008, 10:06
Hello.. I have a Qt application (an agent-based model) with a GUI thread and a "model" thread that runs for hours.

I managed to get a way to stop/pause/resume/ the model thread from the GUI, and also to pass data from the model thread to the GUI for run-time visualisation :)

However now I'd like to "ask" the model thread for a specific information (values for a plot, passing as parameter an integer), and then the model thread would give back the info to the GUI in the usual manner..

The problem is that it doesn't work :(.. when I am inside a function of the model thread ( a QThread derived class) called from the GUI I got different values than if I run the same function from the normal model "path".. like they are different instances, or ??...

Which is the right approach to do something like that?? When I am going ask the model thread for data I just want "read" them..

ciao.. and happy 2008 :cool::cool:
Sylvaticus

marcel
1st January 2008, 10:49
Did you start the thread event loop with exec()? In this case you can send a signal from the GUI thread to the worker thread, basically telling it you need some data. Then the worker thread will send a signal to the GUI thread, with some parameters. This is the safest way.

If you didn't start the event loop and don't want to redesign your code now, then you must have an endless loop in your thread's run method. But you'll have to post some code, or at least describe the way you do things better.



The problem is that it doesn't work :(.. when I am inside a function of the model thread ( a QThread derived class) called from the GUI I got different values than if I run the same function from the normal model "path".. like they are different instances, or ??...

In that function, do you perform some specific thread processing? Because the function will be executed the GUI thread context. This could explain why the members/variables are messed up.



and happy 2008 :cool::cool:

You too.

sylvaticus
1st January 2008, 12:29
I think I got it.. I'll clean the code (I made a mess while tempting) and then I will post here if someone is interested ;-)))

Many thanks,
Sylvaticus

sylvaticus
13th January 2008, 19:14
ok.. this is what I done so far.. it took me longer as the first approach (query executed directly by the GUI trough a signal) was working without problems in Linux but randomly crash in Windows..
Does the following looks as a good approach or it is advisable to be done in an other way??

I have three classes involved, a MainWindow (QMainWindow derived), ThreadManager (QThread derived) and MainProgram (independent class with the model code).

MainWindow starts the thread calling QThread::start().

The QThread::start() call really executes the code in the ThreadManager::run() function that contain MainProgram::run() with all the model code.

The pause and stop system is implemented with the bool ThreadManager::running and bool ThreadManager::stopped variables.
Often (every few seconds) the model code goes to check the status of that variables that can be changed also from the GUI. The code is:


void
ThreadManager::refreshGUI(){
checkQuery(0,0,false);
while (!running){
if(stopped){
break;
}
}
if (stopped){
emit upgradeLogArea("Model has been stopped.");
running= false;
throw(2);
}
}


checkQuery(int, int, bool) is a function that can be called both from the GUI trough a signal or from the running thread trough refreshGUI(), and it is so protected with a QMutex.
It's role is to change/control the status of the query parameters that are members of ThreadManager. The third function parameter is a bool that tell the function if the query parameters should be set (if the query come from the GUI) or if the query should be executed and its results sent back to the GUI with a signal (if the call come from the running thread).
The code is :


void
ThreadManager::checkQuery(int px_ID, int currentLayerIndex, bool newRequest){
QMutexLocker locker(&mutex);
if(newRequest){
pxQueryID = px_ID;
layerQueryPos = currentLayerIndex;
if(stopped){computeQuery(pxQueryID, layerQueryPos);layerQueryPos = -1;} // model is stopped, no way the model thread will do the query work
else{emit publishQueryResults("<i>..wait.. processing query..</i>");} // model is running.. it will be the model thread to execute the query
return;
} else {
if(layerQueryPos<0){
return;
} else {
computeQuery(pxQueryID, layerQueryPos);
layerQueryPos = -1;
return;
}
}
}


The whole code is located at:
http://www.regmas.org/doc/referenceManual/html/classMainWindow.html
http://www.regmas.org/doc/referenceManual/html/classThreadManager.html
http://www.regmas.org/doc/referenceManual/html/classMainProgram.html

Thank you.. I think I finally found a pleace to discuss the Qt programming.. the mailing list looks too technical for a beginner like me... :cool:

Cheers...
Sylvaticus

jacek
17th January 2008, 21:21
The problem might be in automatic connections. QThread object lives in the GUI thread, so automatic connections between widgets and the thread object will behave like if they were direct, which might cause troubles.

This problem was discussed several times, so please search the forum. A few examples:
http://www.qtcentre.org/forum/f-qt-programming-2/t-signalsslots-across-threads-6060.html
http://www.qtcentre.org/forum/f-qt-programming-2/t-help-with-qthread-3943.html

sylvaticus
17th January 2008, 21:49
Thanks for the explanation & the links.....