[Qt-interest] Threading and objects...

William Gordon Rutherdale (rutherw) rutherw at cisco.com
Thu Nov 11 23:19:47 CET 2010


What you're saying might be a good solution.  However, I've found I
prefer to manage threads as follows:

(a)  derive a class from QObject, containing the app code, with
appropriate signals/slots/events
(b)  do NOT derive any class from QThread
(c)  allocate bare QThreads as needed, and do a moveToThread() on each
object that needs to be on a thread
(d)  call start() on each QThread so allocated
(e)  a message or flag can take care of telling the object to stop
executing, when it is time to kill the thread

So I do not subclass from QThread, only from QObject.  The nice thing
about it is that this leaves the flexibility open of moving things into
their own threads or back to the main thread.  All the logic is the same
within each object, as it is just a matter of which thread's event loop
drives its activities.

-Will


> -----Original Message-----
> From: qt-interest-bounces at trolltech.com [mailto:qt-interest-
> bounces at trolltech.com] On Behalf Of BRM
> Sent: 11 November 2010 11:55
> To: qt-interest
> Subject: [Qt-interest] Threading and objects...
> 
> I have been doing quite a bit of multithreading with Qt for a while;
> and
> recently read (on the Qt blogs, a couple months back[1]) about the
> "right way"
> to use QThread; I finally had an opportunity to try it out but am
> running into a
> little problem - at least, I'm getting a message logged. I mainly use
> threads to
> do various tasks - typically ending up with a specific object (e.g. a
> QTcpSocket
> derived class) to a thread; usually something I/O bound or processing
> intensive
> so the one-QObject-to-one-QThread is desired.
> 
> Traditionally, I have derived a new class from QThread, aka QMyThread.
> Within
> the new class's run() I then allocate a new QObject derived class
> (QMyThreadInstance) that does the core work; sometimes passing another
> class
> (e.g. a QTcpSocket derived class) to this new class, which then does
> parent the
> class. The instance class (QMyThreadInstance) does not have a parent,
> and gets
> cleaned up when the event loop exits. The thread class (QMyThread) has
> a series
> of signals for an outside object (e.g. the object spawning the thread)
> to
> connect to, which it then passes on to the instance class
> (QMyThreadInstance).
> As a result, it does take some time to setup these classes, and such.
> Further, I
> don't parent the instance of the QThread (QMyThread) when I allocate
> it.
> (Example 1 below, [2])
> 
> In my new approach, I'm trying to keep the same basic architecture, at
> least for
> now while I get to figure out the new approach - mostly so that it is
> easy to
> revert if I needed to, while at the same time trying to do it the
> "right way"
> with the goal to make it all simpler in the end, perhaps migrating the
> rest of
> the entries to the new method as well. In following this approach, I
> created a
> manager class (QMyThreadManager) that allocates and runs a standard
> instance of
> a QThread - just allocates and starts it. I did parent the QThread to
> the class,
> namely so it gets cleaned up when the manager class goes away. I also
> create an
> instance class (QMyThreadInstance) in the same manner, it is not
> parented; and I
> use moveToThread() on it to move it to the QThread instance that was
> just
> created. When I have another object to give it - e.g. a QTcpSocket
> derived class
> - I first call setParent(NULL) on it, then I do a moveToThread as
well,
> to move
> it to the thread. This is all done before the thread is started, all
of
> which
> (including staring the thread) is in or run (directly or indirectly)
> the class
> constructor.  (Example 2 below, [3] & [4]).
> 
> The problem I am running into is that I am getting the following
> message on the
> new approach:
> 
> QObject::setParent: Cannot set parent, new parent is in a different
> thread
> 
> Now, I'm probably doing something really stupid and just not seeing
it.
> As the
> descriptions above are probably not quite adequate, I put two examples
> below of
> each method.
> 
> TIA,
> 
> Ben
> 
> [1] I think it was this one -
> http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/ - and the
one
> it links
> to but cannot be certain any more. It's been quite a while.
> [2] Example 1: My traditional method
> 
> // QMyThrad is instantiated by another class which does not parent it
-
> but
> connects the signals/slots so it auto-stops/destroys.
> // existing_connection is allocated in the main thread, typically by a
> QTcpServer derived class and retrieved via nextPendingConnection()
> //      additionally, it had setParent(NULL) and
> moveToThread(pointerToInstanceOfQMyThread) called on it
> // only run() is important - it's just the constructor/destructor
> otherwise.
> void QMyThread::run()
> {
>     if (threadRunner == NULL) {
>         if (existing_connection == NULL) {
>             threadRunner = new QMyThreadInstance(NULL); // standard
> constructor
>         } else {
>             threadRunner = new
> QMyThreadInstance(existing_connection,NULL); //
> overloaded constructor
>         }
>     }
>     if (threadRunner != NULL) {
>         existing_connection = NULL; // it's been handed to the object
> if we had
> it.
>         // connect object's signals to our signals
>         // connect our signals to object's slots
>         exec();
>         if (threadRunner == NULL) {
>             delete threadRunner;
>             threadRunner = NULL;
>         }
>     }
> }
> 
> [3] Example 2: new method
> // QMyThreadManager is instantiated by another class which does parent
> it - e.g.
> new QMyThreadManager(this)
> // existing_connection is allocated in the main thread, typically by a
> QTcpServer derived class and retrieved via nextPendingConnection()
> QMyThreadManager::QMyThreadManager(QObject* _parent) :
QObject(_parent)
> {
>     existing_connection = NULL;
>     createThread();
> }
> QMyThreadManager::QMyThreadManager(QTcpSocket* _existing_connection,
> QObject*
> _parent) : QObject(_parent) {
>     existing_connection = _existing_connection;
>     createThread();
> }
> void QMyThreadManager::createThread() {
>     if (actualThread.isNull() == true) {
>         actualThread = new QThread(this);
>     }
>     if (actualThread.isNull() == false) {
>         if (threadRunner.isNull() == true) {
>             if (existing_connection == NULL) {
>                 threadRunner = new QMyThreadInstance(NULL);
>             } else {
>                    // this use to be done by the allocating class
>                 existing_connection.setParent(NULL); // ensure no
> parent is set!
>                 existing_connection.moveToThread(actualThread); //
move
> it to
> the new thread
> 
>                 threadRunner = new
> QMyThreadInstance(existing_connection,NULL);
>             }
>         }
>         if (threadRunner.isNull() == false) {
>             existing_connection = NULL; // it's been handed to the
> object if we
> had it
>             // connect object's signals to our signals
>             // connect our signals to object's slots
>             threadRunner->moveToThread(actualThread); // move it to
the
> new
> thread
>             actualThread->start(); // run the new thread
>         } else {
>             delete actualThread;
>         }
>     }
> }
> 
> [4] Example 2: new method (alternate) - eliminates parenting the
> QThread
> // QMyThreadManager is instantiated by another class which does parent
> it - e.g.
> new QMyThreadManager(this)
> // existing_connection is allocated in the main thread, typically by a
> QTcpServer derived class and retrieved via nextPendingConnection()
> QMyThreadManager::QMyThreadManager(QObject* _parent) :
QObject(_parent)
> {
>     existing_connection = NULL;
>     createThread();
> }
> QMyThreadManager::QMyThreadManager(QTcpSocket* _existing_connection,
> QObject*
> _parent) : QObject(_parent) {
>     existing_connection = _existing_connection;
>     createThread();
> }
> void QMyThreadManager::createThread() {
>     if (threadRunner.isNull() == true) {
>         if (existing_connection == NULL) {
>             threadRunner = new QMyThreadInstance(NULL);
>         } else {
>               // this use to be done by the allocating class
>             existing_connection.setParent(NULL); // ensure no parent
is
> set!
>             existing_connection.moveToThread(&actualThread); // move
it
> to the
> new thread
> 
>             threadRunner = new
> QMyThreadInstance(existing_connection,NULL);
>         }
>     }
>     if (threadRunner.isNull() == false) {
>         existing_connection = NULL; // it's been handed to the object
> if we had
> it
>         // connect object's signals to our signals
>         // connect our signals to object's slots
>         threadRunner->moveToThread(&actualThread); // move it to the
> new thread
>         actualThread.start(); // run the new thread
>     }
> }
> _______________________________________________
> Qt-interest mailing list
> Qt-interest at trolltech.com
> http://lists.trolltech.com/mailman/listinfo/qt-interest




More information about the Qt-interest-old mailing list