[Qt-interest] Long Calculations, QThread Event Loop, Signals & Slots

Michael Jackson mike.jackson at bluequartz.net
Tue Jan 18 15:47:02 CET 2011


On 1/17/11 3:06 PM, in article
28c52c10084f6cd150d800b02783c3b2.squirrel at mail.hostfx.eu, "Andre Somers"
wrote:

> Hi,
> 
> Op Ma, 17 januari, 2011 8:20 pm, schreef Michael Jackson:
> (...)
>> There is still a problem where my calculation object is NOT getting a
>> signal
>> until the long running calculation object is done, at least with
>> QueuedConnections. So here is my general setup:
>> 
>> class LongCalc {
>>    void compute() {
>>         // Stuff that takes 10 minutes to run
>>     }
>> };
>> 
>> Class MyMainWindow : public QMainWindow ....
>> {
>> 
>> void on_GotBtn_clicked()
>> {
>>     t = new Qthread();
>>     calc = new LongCalc();
>>     calc->moveToThread(t);
>>   // When the thread starts its event loop, start the LongCalc going
>>   connect(t, SIGNAL(started()),  calc, SLOT(compute()));
>> 
>> //When the LongCalc ends then tell the QThread to stop its event loop
>>   connect(calc, SIGNAL(finished() ),  t, SLOT(quit()) );
>> 
>> // When the QThread finishes, tell this object that it has finished.
>>   connect(t, SIGNAL(finished()),  this, SLOT( rec_ThreadFinished() ) );
>> 
>>   connect(this, SIGNAL(sig_CancelWorker() ),
>>           calc, SLOT (on_CancelWorker()) );
>> 
>>     t->start();
>> }
>> 
>> private:
>>  QThread* t;
>>  LongCalc* calc;
>> 
>> };
>> 
>> If the "sig_CancelWorker()" signal gets emitted then the slot isn't called
>> until AFTER the "compute()" method has finished. Thinking through what is
>> likely going on makes sense (I think). QThread.run() is called which
>> starts
>> the event loop for that thread. The QThread then sends out the "started()"
>> signal which the LongCalc has hooked up to a slot (compute()) so the
>> "Compute()" method now runs which effectively blocks the event loop from
>> running? Is that correct?
> Yes, that diagnosis is correct.
> 
>> I thought I knew what I was supposed to do but
>> now
>> it seems like a need yet a third thread to actually run the long
>> computation
>> while I have an intermediate thread that has an event loop that is running
>> to deliver the messages to the third thread?
> 
> No, that would not help.
> 
>>   My mind wants to create some sort of "Queue" system like a
>> Producer-Consumer" so that the slot can return right away and then ask a
>> the
>> other sleeping thread to wake up and calculate. This just smells like I am
>> missing something obvious with Qt and Threads.
> Indeed. You're talking about reimplementing a rudimental eventloop in your
> calculation. Not a good plan usually.
> 
>>   More thoughts and clarifications would just be wonderful.
> 
> There are several solutions to your problem. The first is the simplest.
> Just create a cancel flag in your worker object that is checked regulary
> in the calculation. You set it from outside your thread using a direct
> method call or a signal-slot connection with the Qt::DirectConnection
> flag. Synchronization doesn't matter here, all that can happen is that
> your worker just passed checking the flag when you set it, which causes
> one extra calculation step. No biggy, just don't expect the thread to
> terminate immediately, only quickly.
> 
> The other solution is to make sure your eventloop *does* run. You can do
> that by splitting the calculation into pieces, and returning to the
> eventloop after each piece. You can trigger the next piece by using a
> singleshot, 0ms timer for instance. Alternatively, you could use
> processEvents on your thread local eventloop. I am not a big fan of this
> method though.
> 
> Note that neither of these simplify the first solution though. You will
> still need a cancel flag. As long as you don't expect much communication
> from your main thread towards the worker thread than a cancel flag, the
> first solution will work fine. Note that you can still send event from the
> worker object to the GUI thread (for things like progress updates, for
> instance). As long as the GUI thread is not blocked, they will arrive just
> fine.
> 
> Also note that if you have one big, blocking operation, the approach of
> moving a QObject on a QThread doesn't help you a lot. A QThread subclass
> with a reimplemented run() method that simply does the long calculation
> and without an eventloop works just as well.
> 
> André


I did try my signal/slot connection with a "DirectConnection" and it did
work how I was expecting it would. The long calculation thread eventually
stopped itself and exited normally. After all the discussions with Threads,
Event Loops, moveToThread and all of that I just wanted to make sure that I
wasn't setting myself up for some subtle bugs later on. I think I will just
go with a DirectConnection to the "cancel" slot as that is pretty much the
only communication from the Gui Thread to the Calc thread. I do have
progress messages and progress percentages flowing FROM the calc thread TO
the GUI thread just fine.
   Thanks for the clarification and Sanity check. I do appreciate the time
you took explaining the various alternatives.

Mike Jackson
Www.bluequartz.net




More information about the Qt-interest-old mailing list