Andy Shaw

Qt Commercial Support Weekly #9: Common pitfalls with QThread

1/3/2012 4:44 PM  | Posted by: Andy Shaw

After an admittably brief hiatus the Qt Commercial Support weekly post is back in full swing for the new year!  To start off for the new year I will be covering threads and how they tend to get misused generally which can lead to problems later on.  This may be not be new information to a fair number if not the majority of you but it isn't entirely uncommon that people get tripped up on these things.

 

Problem #1: Putting slots inside the thread subclass and using them from objects inside the run() function.


It is an easy mistake to make as you already need to subclass QThread in order to be able to reimplement run() which is where all the code to be executed in the other thread should go.  But if you are adding slots as members of the QThread subclass then they will exist in a different affinity to the thread you are using.  When run() is invoked then it is inside another thread and any objects created in there belong to that thread.  Whereas the QThread object itself belongs to the thread that it was actually created in which is typically the main thread.

Therefore if you want to ensure the slots are invoked in the right thread then you should subclass QObject and add the slots as members to that subclass and create an instance of the QObject subclass inside the run() function.  This will ensure they exist in the same thread then.

 

Problem #2: Creating an object inside the thread's run() function and passing 'this' as the parent.

 

It is a natural thing to do as we are used to passing in this when creating a widget or object so that we don't need to worry about the parent-child hierarchy and cleaning up after ourselves.  However, this causes a problem within the other thread because in this context - 'this' is the QThread object which belongs to a different thread.  In order to ensure there is still a parent-child relationship then you can still pass a parent, but it should be an object created/owned by the thread.

 

Problem #3: Causing an update on a widget inside the thread's run() function.

 

This may seem obvious as something you shouldn't be doing because it is documented as such in the Qt documentation but it does slip from people's minds and sometimes this sort of thing can appear to work and subseqently get forgotten until later on.  This can be something like triggering a change to a model or even setting a model on a view.  In some cases it can be safe to prepare something before passing it on to the other thread, with moveToThread() and then doing the call that triggers the update in the main thread.  But it is never safe to do it directly.  It might work but it is likely to have problems later on.

 

So those are the three main problems to watch out for, there are some more things to watch out for which you can find in the documentation at http://doc.qt.nokia.com/threads.html.

 

Before I sign off for another week, I would like to request feedback from our customers out there, we do value any feedback we get from you be it for a particular case or for support in general.  Especially if we send a patch to you because it helps us to know if the patch solves the problem or not, particularly if it introduces any problems as we can only test it in a limited context in support.  Sometimes this feedback can mean that we can submit a patch safely back into Qt or it will go a long way to helping the developers solve the problem in the next release.

Tags: framework Qt

Comments:

teki | 1/4/2012 2:36 AM
The wiki has a very good article about the topic: http://developer.qt.nokia.com/wiki/Threads_Events_QObjects

kapinter | 1/4/2012 10:06 AM
Good article! Some addition: http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/

charley | 1/5/2012 7:21 PM
Agree with @kapinter, good article, important things to think about (would like to see more like this), and the Qt4+ way-to-go is to no longer derive from QThread (see link referenced by @kapinter).

Andy Shaw | 1/6/2012 1:37 PM
Actually as Brad comments in the blog post later on, he is not saying that subclassing QThread is wrong, but doing things like the #1 case is actually wrong, but the reason people do it because they are forced to subclass QThread. Although subclassing QThread is no longer necessary to some extent, there is nothing actually wrong about doing it as long as you are careful :)

sbtree | 1/19/2012 6:35 PM
How can I do in the following situation: MyObject *obj = new MyObject; //create a object somewhere, which has a slot, named "Test()" in run() of thread A: YourObject *yourObj = YourObject(); connect(yourObj, SIGNAL(YourSignal()), obj, SLOT(test())); in run of thread B: YourObject *yourObj = YourObject(); connect(yourObj, SIGNAL(YourSignal()), obj, SLOT(test())); can the code work? if yes, how?

James Gibbons | 1/23/2012 9:03 PM
You can also fix problem #1 by using the moveToThread method like this: // move event processing for thread onto thread // this makes events occur on the thread instead of main window event loop rtThread.moveToThread(&rtThread); A rather detailed example is given in this source download: http://www.folding-hyperspace.com/zips/Qt_RealtimeIO_App.zip From this page: http://www.folding-hyperspace.com/program_tip_14.htm But there is also something one must also watch out for as discussed here: http://www.folding-hyperspace.com/program_tip_15.htm Perhaps this should be item #4.

Butterfly | 1/24/2012 11:06 PM
Please keep thowring these posts up they help tons.

Andy Shaw | 1/26/2012 11:17 AM
sbtree: It works because the two objects are in separate threads which means that the connection between the two is a queued connection. However this means that the Thread A run() function needs to ensure events are processed so either periodically call QApplication::processEvents() inside run() or call exec() to start an event loop. Then it will be able to process any events posted to it from Thread B which would happen when the signal gets emitted.

Andy Shaw | 1/26/2012 11:18 AM
James Gibbons: You are right that moveToThread() can be used as well, you have to ensure that it is called from the owning thread as it can only be pushed to another thread not pulled from one.

Add new comment:

User verification Image for user verification  
     

Tags

Archive

Authors

Pasi Matilainen

Pasi is a Software Specialist working at Digia, Qt Commercial R&D and he concentrates on Mac OS X development. Pasi holds an M.Sc. degree in Information Technology from the Tampere University of Technology, Finland.

Tarja Sundqvist

Tarja is a Senior Software Engineer in the Digia, Qt Commercial Support team. She has been working in Digia for over 10 years in various positions: software development, testing, error management. Now, Tarja is focusing on helping Qt Commercial customers with their daily Qt problems on Windows and Linux platforms. Tarja holds an M.Sc. degree in Information Processing Science from the University of Oulu, Finland.

Akseli Salovaara

Akseli is a Software Specialist at Digia, Qt Commercial R&D and is responsible for the Qt Commercial releases and deliveries. Akseli holds an B.Sc. degree in Information Technology from the University of Applied Sciences in Jyväskylä, Finland.

Samuli Piippo

Samuli is a Software Specialist at Digia, Qt Commercial R&D with a concentration on  embedded Linux and RTOS development. Samuli holds an M.Sc. degree in Information Processing Science from the University of Oulu, Finland.

Katherine Barrios

Katherine is the Marketing Manager at Digia, Qt Commercial. She is responsible for getting the word out about Qt Commercial to the Qt ecosystem and working together with our customers and the Qt community to further extend the love for Qt on desktop and embedded. She was previously employed at Nokia, Qt Development Frameworks as Program Marketing Manager and is based in Oslo, Norway.

Sami Makkonen

Sami is a Senior Product Manager working at Digia, Qt Commercial R&D and he is responsible for the product planning including new feature development and enhancements to existing functionality. Sami holds an M.Sc.(Econ.) degree in Computer Science.

Andy Shaw

Andy is the Head of Support at Digia, Qt Commercial and has been working with Qt and supporting customers using Qt for 11 years.  He thrives on solving customer problems and getting feedback from them.

Tuukka Turunen

Tuukka is the Director of R&D at Digia, Qt Commercial and is responsible for the planning, creation, verification and delivery of the Qt Commercial product. Tuukka holds a M.Sc.(Eng) and Licentiate of Technology degrees in Computer Science.

Qt Commercial Team