[Qt-interest] connection between qthreads blocks my gui

K. Frank kfrank29.c at gmail.com
Wed Dec 15 00:15:06 CET 2010


Hello Marek -

2010/12/14 franki <franki at franki.eu.org>:
> Tuesday 14 of December 2010 20:06:58 J-P Nurmi napisał(a):
>> On Tue, Dec 14, 2010 at 8:25 PM, franki <franki at franki.eu.org> wrote:
>> > ...
>> > I have some gui class (mainClass), inside that class I created two
>> > classes which subclass QThread, one of which is sending/receiving data
>> > from rs232, lets say rs232Thread, second one is sending signal to start
>> > reading from rs232,lets say cronThread. Connection is defined inside
>> > mainClass like this:
>> > connect(cronThread,SIGNAL(startChecking()),rs232Thread,SLOT(readWrite()),
>> >Qt::QueuedConnection)
>> >
>> > Problem is, that this readWrite function blocks my entire gui when
>> > running, and as I read somewhere in case of QueuedConnection, the SLOT is
>> > executed inside receiver's thread, so why is this blocking my gui?
>> > ...
>> > What am I doing wrong? Is this a problem that connection between this two
>> > threads is defined inside mainClass (which is gui thread) ? Or there is
>> > something else?
>>
>> Hi,
>>
>> Be careful with having slots in QThread subclasses. Check this
>> arcticle: http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/.
>
> I have read this
> ...
> So now I see some options

Warning -- I haven't fully absorbed what you are trying to do,
so my general comments may not apply precisely to your
specific situation.

> 1. Simplest (but I'm not sure if it meets all my needs) is to call
> moveToThread(this) inside class contructor, then all functions defined in
> class will move to separate thread and QueuedConnection signal-slot should
> work

This should work.  I think it's a fine idiom for using queued
connections in a QThread-derived class.

It has the disadvantage that your QThread-derived class -- let's say
Rs232Thread -- now mixes together two separate concerns:  First, the
class manages a thread of execution (because that's what QThread
does); and second the class manages RS-232 communication
(because presumably that's what Rs232Thread does).

It has the advantage that it is somewhat less verbose than a design
in which you break out the RS-232 management into another class.

(Object-oriented purists would consider the disadvantage sufficiently
compelling to avoid this approach, but I'm not sure that I would go
so far as to say that this approach is "doing it wrong.")

> 2. Rewite code to make my classes derived from QObject, as I need them to send
> signals after work done, and slots are needed of course, and after creating
> the object move class to separate thread

I imagine here that you define two QObject-derived classes:  Rs232Manager,
and Rs232Cron.  This is the separation-of-concerns approach where you
don't mix the "real" work done by your classes (the RS-232 stuff) with
thread management (the job of QThread).

Note, however, that you can avoid an explicit call to moveToThread by
using what I think is a common Qt threading idiom:  Derive a class,
Rs232Thread, from QThread, and have Rs232Thread instantiate an
Rs232Manager in its run method.  The Rs232Manager now has affinity
for the thread of execution managed by Rs232Thread, so you signal
and slot connections to Rs232Thread will be queued connections, and
won't block your main gui thread.

This is a little more modular that option 1 (keeps the purists happy),
but is a little more verbose.

> 3. Someone has mentioned using RegisterdThreads and then all slots will be
> executed in just created thread

I don't see the need for this given what (I think) you're trying to do.

> 4. for these people who were claiming that they never have to use moveToThread
> I suppose they were doing some sort of job queue on their own, right? So far
> I was using some flags (regular variables) or QWaitCondition in endless loop
> inside run() function, but I found it cumbersome when dealing with many jobs
> to do.

I think in order not to need to call moveToThread, you need to use option 2.
If you don't want your gui thread to block, your RS-232 slots need to be
called over queued connections, so your Rs232Manager class has to have
affinity for a thread of execution other than the gui thread.  So it either
needs to be instantiated in another thread (option 2) or it needs to be
moved to another thread by calling moveToThread (e.g., option 1).

> In the end, what would be the best way?

Assuming that your needs are a simple as you describe, I think both
options 1 and 2 are fine.  If your application is fairly small (and not
expected to grow much over time), I would lean towards options 1
for its economy.  If your application is larger or is likely to need
ongoing maintenance, I would lean towards options 2 for its greater
modularity.

> What I need to implement in app is like this.
> When it initialize app, it queries all devices through rs232 which takes about
> 10 seconds. This is easy - put all work inside run() of a rs232 thread and
> receive signals notifying about every device. Such a general checking is
> invoked every five minutes, so I have function that sets variables like
> checkSomething and starts rs232 thread (if its not working). However, between
> these general checkings, if user move QDial (or press button which has
> autoRepeat) on the gui it has to send signals to change something in device,
> because it takes about 100 miliseconds for rs232 to accomplish single change,
> and QDial has tracking enabled I need rs232 to buffer this subsequent changes
> and apply them to device without gui freezing. So, the mechanism with
> queueing events for rs232 (which works in separate thread) is very attractive
> to me, but question: am I missing something, or should I go stright to number
> 2 solution?
>
> best regards
> Marek

Good luck.


K. Frank




More information about the Qt-interest-old mailing list