Working with threads
-
I'm sort of at my wits end, at this point I'd rather ask for guidance than create some sort of monster. The idea is simple itself, I'm not working on a complex application, but well; I can tackle GUI stuff and other things, but when it comes to threads it's a subject I need to eventually need to touch and learn.
I have a class that moves to a whole thread, not much to see in this class as it's a setup of sorts.
subscriptionWorker = new ProcessSubscriptions(nam); subscriptionWorker->moveToThread(subscriptionWorkerThread); nam->moveToThread(subscriptionWorkerThread); QTimer *timer = new QTimer; connect(subscriptionWorkerThread,SIGNAL(started()), subscriptionWorker, SLOT(process())); connect(this,SIGNAL(queueAllUpdate()),subscriptionWorker,SLOT(queueAll())); connect(timer,SIGNAL(timeout()),subscriptionWorker,SLOT(queueAll())); timer->start(600000); // TODO: move to user-defined subscriptionWorkerThread->start();
So basically the worker just processes incoming requests. Initially I just thought of using a QMutex, and QWaitCondition. In a way I don't want to stop the thread completely. I want to be able to interact with it through Slots and Signals mechanism so when I tell it to queue, it will queue things.
P.S this is an example, not real code.
void ProcessSubscriptions::process() { qDebug() << "Starting Subscription Worker Thread "; // get list of subscriptions // process said list //item.processRequest(); forever { QWaitCondition waitforit; QQueue<QString> queue; if(!queue.isEmpty()) { // process data } else { // qwaitcondition waitforit.wait(&mutex); } } }
I'm guessing that in a slot I will create a method called
ProcessSubscriptions::resume
then dowaitforit.wakeOne()
and it will stop blocking? Would it resume? If so will I have access to keep interacting with the worker from other GUI-related calls? (regardless if waitforit is waiting?)The flow of the ProcessSubscription is rather simple: Start thread, process data, emit data to other classes through signals), wait and resume.
Another question I had related to threads was about NAM. I plan to add proxy support soon and configure NAM to use it, according to the documentation one NAM is enough for the whole application. As you can see above the code you notice that I move nam to the new thread, but if I require (through sharing the pointer as needed) move it safely through
moveToThread
, will it finish the requests then swap threads, finish the request and swap back?It feels like I'm complicating things and I should just create another NAM in the new class... but, as always I'd rather hear from more seasoned people and see if I can piece the puzzle together. I have no priority on NAM related stuff, I'd like to hear more if I'm right on track with the snippets. Lastly, any good book recommendation about threads and Qt (preferably) is welcomed.
-
Hi,
First things first. Your worker thread must have EITHER an event loop OR a custom infinite loop (
forever {}
). You cannot have both at the same time.The idea behind event loops in multithreading is:
- The event loop blocks/waits for you. You should not use mutexes, wait conditions, etc. The thread is "asleep" until the event loop receives a signal. At that point, the thread wakes up, runs the slot(s), and then goes to sleep again.
- Data is transferred between threads using signal/slot parameters.
The idea behind custom infinite loops is:
- You must provide your own locks/waits. The thread goes to sleep when it reaches a QMutex/QWaitCondition/etc. until someone unlocks it.
- Data is transferred between threads using thread-safe variables.
- Note: Data can be transferred OUT of the thread using signals, but cannot be transferred INTO the thread using signals -- an event loop is required to receive signals.
Here's some reading material to get you started:
@David.G said:
void ProcessSubscriptions::process() { qDebug() << "Starting Subscription Worker Thread "; // get list of subscriptions // process said list //item.processRequest(); forever { QWaitCondition waitforit; ... } } }
In this code,
ProcessSubscriptions::process()
never returns. Since you don't return control to the event loop, that means the thread can no longer receive signals. -
Thanks for the reply, @JKSH.
I've been wondering, I'll remove the code of
forever {}
, what would be a way to constantly poll if there's data to process? Should I just use a timer every 1 second to keep poking theprocess
method with a simple boolean that returns if process is already running?. -
@David.G said:
Thanks for the reply, @JKSH.
I've been wondering, I'll remove the code of
forever {}
, what would be a way to constantly poll if there's data to process? Should I just use a timer every 1 second to keep poking theprocess
method with a simple boolean that returns if process is already running?.You're welcome. :) Yes, using a timer is a good way to poll.