PDA

View Full Version : Thread Communication not doing so well



BatteryCell
14th June 2007, 18:49
Hello, basically I am writing an application (client) that communicates with a server, which I did not write; and I want all the calls to be asynchronous. So I create two threads, a GUI thread and then the mainloop thread (mainloop uses server code, does not use QThread, communicates through QSockets). That all works perfectly. However, there is one job that my client does that takes a lot of cpu, so I wanted to offload it onto a third worker thread. However, the worker thread needs to make a call to the mainloop thread which then redirects to the gui thread. So like:

OpenThread(Worker) -> getStuff(mainloop) -> useStuff(gui)

However, if I place exec() after the call to getStuff then I get QSocket problems, but if I put it before then nothing happens. Does anybody have any idea as to how I could make this work?

marcel
14th June 2007, 19:03
This is nothing more than a small? design error.
If you call exec before, the thread will remain in exec until you call exit.
Exec must be called the last one in this case.

Isn't getStuff a slot in mainloop? Well, it should be. At least it should be called in a slot connected to a signal from the worker thread.

BatteryCell
14th June 2007, 19:42
getStuff is actually kind of weird, its a function that queries the server and then the results are passed as arguments to a slot in the GUI thread. The server lookup itself actually takes a small amount of time (its the GUI method that takes forever), so do you think it would be advisable to just call the getStuff from GUI and then useStuff would be done in the helper thread? That way I don't have to communicate with the server (where the socket errors are coming from). I think that I will try that and get back to you.

Thanks for the help :)

marcel
14th June 2007, 20:06
Think about this a little: emit a signal from the worker thread. The signal will be connected to a slot in mainloop. In this slot you call getStuff and after it's done, from this slot emit a signal which is connected to the GUI thread. The main thread can take the data and do useStuff.

But remember to call exec in the main loop thread, so you start the event loop in this thread.
Also, you must call mainloop->moveToThread(mainloop) in its parent thread, after main loop is started. This way you move the event handling for main loop in its own context.
Actually, this might have been the problem from the very beginning.


Regards

BatteryCell
15th June 2007, 03:31
Hm, the problem is that the part that actually takes a large amount of time is the actual gui work itself. Its a QTreeWidget and I am inserting a large number of nodes into it, but they have to be placed correctly. And the insertion of the nodes takes n^2 time, which can take a while. Could I do this from the worker thread?

marcel
15th June 2007, 05:15
Please read this first: http://www.qtcentre.org/forum/f-qt-programming-2/t-thread-freezing-gui-7322.html

BatteryCell
17th June 2007, 00:24
Thanks! The other thread told me enough to get it almost all set up. Basically its like this: (cond is a QWaitCondition, and mutex is a QMutex)

Main Thread:
Signals: getReady(int), insert(QString*, QString*, QString*)
Slots: updateTree(QTreeWidget*)

Worker Thread:
Signals: done(QTreeWidget*)
Slots: prepare(int), insertOne(QString*,QString*,QString*)

insertOne(...) sets the Worker Threads variables, and then if it isn't running starts it, otherwise it calls cond.wakeOne().
prepare(...) sets total.

So the sequence would be:
1) Main Thread -> getReady()
2) Worker Thread -> prepare()
3)
--- a lot of times
Main Thread ->insert()
Worker Thread -> insertOne()
---
4) Worker Thread -> done()
5) Main Thread -> updateTree()

and sudo code for Worker::run():


forever {
mutex->lock()
...
insert into tree
...
mutex->unlock()
if (numDone == total) {
emit done(treeWidget);
return;
}

mutex->.lock();
cond->wait(mutex);
mutex->unlock();

}


If I run this on a data set of about 4000 around 3500 are inserted correctly, however, there are about 500 signals from the main thread that get to the slot, and wakeOne, but nothing happens (the forever loop doesn't get woken). Why is this?

BatteryCell
19th June 2007, 01:08
Update:
I fixed it thanks to KISS. Basically instead of emitting a signal with the information, then inserting it, then waiting for the next signal , etc... etc... I just recieved all the signals with info and pushed the information onto stacks. Then, once all the information was transmitted (not very time consuming), I started the thread and had it insert them all (popping them as is went) untill the stacks were empty.

Thanks for all the help ! :D