[Qt-interest] Example of "moveToThread (this)" idiom -- legal?

Clinton Stimpson clinton at elemtech.com
Sun Jan 2 04:40:39 CET 2011


For me, it is simply that QThread isn't documented as thread-safe or 
reentrant.  So, if a QThread moves itself off the original parent 
thread, I don't see how the original parent thread can call 
QThread::wait(), QThread::isFinished(), etc... without calling functions 
that aren't thread-safe.

Clint

On 01/01/2011 07:38 PM, K. Frank wrote:
> Hello List!
>
> According to my understanding of the Qt threading model,
> I believe that our so-called "moveToThread (this)" idiom is
> technically legal.  I'd like to get some feedback on whether
> this is correct.
>
> This is a follow-up to a number of questions about threading
> that come up from time to time, most recently this:
>
>     http://lists.qt.nokia.com/pipermail/qt-interest/2010-December/030053.html
>
> To help make things concrete, I''ve put together a minimal
> example (see below).
>
> The basic question is whether it is legal to derive a worker
> class from QThread, and include the business logic and any
> necessary signals and slots in the QThread-derived class
>
> (I want to set aside the separate question of whether such an
> approach is good design,and focus on whether it is technically
> correct.)
>
> In the following example, I derive a worker-thread class from
> QThread, and include in it signals and slots, and (trivial)
> business logic.  I use a call to QThread::sleep() to emulate
> an expensive computation or blocking call.
>
> The basic point is that in order for the worker thread's slots
> to be actually executed by the worker thread's thread of
> execution (rather than by the main gui thread), the worker
> thread must be "moved" to itself.  In the example, this is
> done in the worker thread's constructor:
>
>     class SquareThread : public QThread {
>       Q_OBJECT
>       public:
>         SquareThread() { moveToThread (this); }
>         // ...
>     };
>
> This is what I've called the "moveToThread (this)" idiom.
>
> As far as I can tell the example works just fine, the "work"
> gets handed off to the worker thread for execution, and the
> gui remains responsive while the worker thread is busy.
>
> Any thought or insight would be greatly appreciated.
>
> (I do agree that there are some design trade-offs using this
> approach, primarily the loss of the "separation of concerns"
> that is one of the goals of object-oriented design.
>
> If you look at Hughes's "You’re doing it wrong…" article,
> http://labs.qt.nokia.com/2010/06/17/youre-doing-it-wrong/
> I believe that this design issue underlies Hughes's main
> complaint, although he doesn't say so in so many words.
> Hughes also does not state outright that there is anything
> technically wrong with the "moveToThread (this)" approach.
>
> My question is not whether this idiom is object-orientedly
> impure, but rather whether it is technically correct and works
> as desired and expected.  For me it seems to.)
>
>
> The example consists of two files:  thread_example.h and
> thread_example.cpp.
>
> I build it by placing the two files in a clean directory, and
> running:
>
>     qmake -project
>     qmake
>     mingw32-make
>
> (I am using 32-bit mingw g++ 4.4.1 and Qt 4.6 on 64-bit windows 7.)
>
>
> // thread_example.h
>
> // illustrate "moveToThread (this)" idiom
>
> #include<QtGui>
>
> class SquareThread : public QThread {
>    Q_OBJECT
>    public:
>      SquareThread() { moveToThread (this); }
>    signals:
>      void send_result (int result);
>    public slots:
>      void receive_value (int value) {
>        sleep (3);
>        emit send_result (value * value);
>      }
> };
>
> class SquareDialog : public QDialog {
>    Q_OBJECT
>    public:
>      SquareDialog (QWidget *parent = 0) : QDialog (parent) {
>        value_box = new QSpinBox (this);
>        value_box->move (40, 20);
>
>        calc_button = new QPushButton ("calculate square", this);
>        calc_button->setGeometry (110, 20, 90, 20);
>
>        QLabel *value_label = new QLabel ("value:", this);
>        value_label->move (40, 50);
>
>        QLabel *result_label = new QLabel ("result:", this);
>        result_label->move (110, 50);
>
>        value_edit = new QLineEdit (this);
>        value_edit->setGeometry (40, 70, 40, 20);
>        value_edit->setReadOnly (true);
>
>        result_edit = new QLineEdit (this);
>        result_edit->setGeometry (110, 70, 40, 20);
>        result_edit->setReadOnly (true);
>
>        resize(240, 110);
>
>        SquareThread *square_thread = new SquareThread;
>
>        connect (calc_button, SIGNAL(clicked()), this, SLOT(calc_square()));
>        connect (this, SIGNAL(send_value (int)), square_thread,
> SLOT(receive_value (int)));
>        connect (square_thread, SIGNAL(send_result (int)), this,
> SLOT(receive_result (int)));
>
>        square_thread->start();
>      }
>    signals:
>      void send_value (int value);
>    public slots:
>      void calc_square() {
>        int v = value_box->value();
>        value_edit->setText (QString::number (v));
>        calc_button->setEnabled (false);
>        calc_button->setText ("thinking...");
>        result_edit->setText ("- ??? -");
>        emit send_value (v);
>      }
>      void receive_result (int result) {
>        result_edit->setText (QString::number (result));;
>        calc_button->setText ("calculate square");
>        calc_button->setEnabled (true);
>      }
>    private:
>        QSpinBox *value_box;
>        QPushButton *calc_button;
>        QLineEdit *value_edit;
>        QLineEdit *result_edit;
> };
>
>
> // thread_example.cpp
>
> // illustrate "moveToThread (this)" idiom
>
> #include<QtGui>
>
> #include "thread_example.h"
>
> int main(int argc, char *argv[]) {
>    QApplication a(argc, argv);
>
>    SquareDialog main_window;
>    main_window.show();
>
>    return a.exec();
> }
>
>
> Thanks for your thoughts, and Happy Hacking!
>
>
> K. Frank
> _______________________________________________
> Qt-interest mailing list
> Qt-interest at qt.nokia.com
> http://lists.qt.nokia.com/mailman/listinfo/qt-interest




More information about the Qt-interest-old mailing list